Merge remote-tracking branch 'origin/main' into v3_issue_612-integrationtest

This commit is contained in:
iadgovuser58 2023-10-19 13:50:31 -04:00
commit e2507d5641
58 changed files with 2436 additions and 2424 deletions

View File

@ -0,0 +1,19 @@
FROM ubuntu:22.04
RUN apt-get update -y && apt-get upgrade -y && apt-get clean -y
# Install packages for building HIRS ACA
RUN apt-get -y install openjdk-17-jdk mariadb-server
RUN apt-get -y install git curl nano cron
# Ports needed for system-level tests
EXPOSE 8080
EXPOSE 8443
# Checkout HIRS main branch and run gradlew to install gradlew dependencies, then delete HIRS
# Use '--depth=1' so as to not download the history of all commits
RUN git clone -b main --depth=1 https://github.com/nsacyber/HIRS.git /hirsTemp
WORKDIR "/hirsTemp"
RUN /bin/bash -c './gradlew clean build'
WORKDIR "/"
RUN rm -rf /hirsTemp

View File

@ -0,0 +1,69 @@
name: HIRS build and packages for Linux
on:
push:
branches:
- '*v3*'
- 'main'
workflow_dispatch:
jobs:
# run the package script for HIRS ACA, Provisioners, tcg_rim_tool, and tcg_eventlog_tool
Package_linux:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: directory setup
run: |
mkdir -p artifacts/jars
- name: install dependencies
run: |
sudo apt-get update
sudo apt-get install git curl nano cron mariadb-server
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Execute Gradle build
run: |
./gradlew build;
./gradlew bootWar;
./gradlew buildDeb;
./gradlew buildRpm;
cp HIRS_AttestationCAPortal/build/libs/*.jar artifacts/jars/.
cp HIRS_AttestationCA/build/libs/*.jar artifacts/jars/.
cp HIRS_Utils/build/libs/*.jar artifacts/jars/.
cp HIRS_Structs/build/libs/*.jar artifacts/jars/.
- name: Archive RPM files
uses: actions/upload-artifact@v3
with:
name: RPM_Files
path: HIRS_AttestationCAPortal/build/distributions/*.rpm
if-no-files-found: error
- name: Archive DEB files
uses: actions/upload-artifact@v3
with:
name: DEB_Files
path: HIRS_AttestationCAPortal/build/distributions/*.deb
if-no-files-found: error
- name: War files
uses: actions/upload-artifact@v3
with:
name: WAR_Files
path: HIRS_AttestationCAPortal/build/libs/HIRS_AttestationCAPortal.war
if-no-files-found: error
- name: JAR_Files
uses: actions/upload-artifact@v3
with:
name: JAR_Files
path: artifacts/jars/
if-no-files-found: error

0
10
View File

View File

@ -37,6 +37,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

View File

@ -8,9 +8,8 @@ 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.TPM2ProvisionerStateRepository;
import hirs.attestationca.persist.provision.CertificateRequestHandler;
import hirs.attestationca.persist.provision.IdentityClaimHandler;
import hirs.attestationca.persist.provision.IdentityRequestHandler;
import hirs.attestationca.persist.provision.CertificateRequestProcessor;
import hirs.attestationca.persist.provision.IdentityClaimProcessor;
import hirs.attestationca.persist.service.SupplyChainValidationService;
import hirs.structs.converters.StructConverter;
import lombok.extern.log4j.Log4j2;
@ -62,9 +61,8 @@ public abstract class AttestationCertificateAuthority {
private final PolicyRepository policyRepository;
private final TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository;
private CertificateRequestHandler certificateRequestHandler;
private IdentityClaimHandler identityClaimHandler;
private IdentityRequestHandler identityRequestHandler;
private CertificateRequestProcessor certificateRequestHandler;
private IdentityClaimProcessor identityClaimHandler;
/**
* Constructor.
@ -109,19 +107,13 @@ public abstract class AttestationCertificateAuthority {
this.policyRepository = policyRepository;
this.tpm2ProvisionerStateRepository = tpm2ProvisionerStateRepository;
this.certificateRequestHandler = new CertificateRequestHandler(supplyChainValidationService,
this.certificateRequestHandler = new CertificateRequestProcessor(supplyChainValidationService,
certificateRepository, deviceRepository,
privateKey, acaCertificate, validDays, tpm2ProvisionerStateRepository);
this.identityClaimHandler = new IdentityClaimHandler(supplyChainValidationService,
this.identityClaimHandler = new IdentityClaimProcessor(supplyChainValidationService,
certificateRepository, referenceManifestRepository,
referenceDigestValueRepository,
deviceRepository, tpm2ProvisionerStateRepository, policyRepository);
this.identityRequestHandler = new IdentityRequestHandler(structConverter, certificateRepository,
deviceRepository, supplyChainValidationService, privateKey, validDays, acaCertificate);
}
byte[] processIdentityRequest(final byte[] identityRequest) {
return this.identityRequestHandler.processIdentityRequest(identityRequest);
}
byte[] processIdentityClaimTpm2(final byte[] identityClaim) {

View File

@ -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;
// }
}

View File

@ -71,28 +71,6 @@ public class RestfulAttestationCertificateAuthority extends AttestationCertifica
referenceDigestValueRepository, policyRepository, tpm2ProvisionerStateRepository);
}
/**
* Processes a given IdentityRequestEnvelope and
* generates a IdentityResponseEnvelope. In most cases,
* a client will generate the request using the TPM "Collate Identity" process.
*
* Wrap the {@link AttestationCertificateAuthority#processIdentityRequest(byte[])}
* with a Spring {@link org.springframework.web.bind.annotation.RequestMapping}. Effectively, this method then will allow spring to
* serialize and deserialize the request and responses on method invocation and
* return, respectively.
*
* @param identityRequest generated during the collate identity process with a Tpm
* @return response for the request
*/
@Override
@ResponseBody
@RequestMapping(value = "/identity-request/process",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public byte[] processIdentityRequest(@RequestBody final byte[] identityRequest) {
return super.processIdentityRequest(identityRequest);
}
/**
* Listener for identity requests from TPM 2.0 provisioning.
*

View File

@ -5,8 +5,6 @@ package hirs.attestationca.persist;
*/
public interface RestfulInterface {
byte[] processIdentityRequest(byte[] identityRequest);
byte[] processIdentityClaimTpm2(byte[] identityClaim);
byte[] processCertificateRequest(byte[] certificateRequest);

View File

@ -40,7 +40,7 @@ public abstract class AbstractEntity implements Serializable {
@Column (name = "create_time")
@ColumnDefault(value = "CURRENT_TIMESTAMP")
@Generated(GenerationTime.INSERT)
private Date createTime;
private Date createTime = new Date();
/**
* Default empty constructor is required for Hibernate. It is protected to
@ -67,6 +67,9 @@ public abstract class AbstractEntity implements Serializable {
* @return creation time
*/
public Date getCreateTime() {
if (createTime == null) {
createTime = new Date();
}
return (Date) createTime.clone();
}

View File

@ -17,4 +17,5 @@ public interface CACredentialRepository extends JpaRepository<CertificateAuthori
List<CertificateAuthorityCredential> findBySubject(String subject);
List<CertificateAuthorityCredential> findBySubjectSorted(String subject);
CertificateAuthorityCredential findBySubjectKeyIdentifier(byte[] subjectKeyIdentifier);
CertificateAuthorityCredential findBySubjectKeyIdString(String subjectKeyIdString);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -20,7 +20,7 @@ import java.util.Date;
@NoArgsConstructor
@Entity
public class TPM2ProvisionerState {
private static final int MAX_BLOB_SIZE = 65535;
private static final int MAX_BLOB_SIZE = 16777215;
@Id
private Long firstPartOfNonce;
@ -88,7 +88,7 @@ public class TPM2ProvisionerState {
/**
* Convenience method for finding the {@link TPM2ProvisionerState} associated with the nonce.
*
* @param TPM2ProvisionerStateRepository the {@link TPM2ProvisionerStateRepository} to use when looking for the
* @param tpm2ProvisionerStateRepository the {@link TPM2ProvisionerStateRepository} to use when looking for the
* {@link TPM2ProvisionerState}
* @param nonce the nonce to use as the key for the {@link TPM2ProvisionerState}
* @return the {@link TPM2ProvisionerState} associated with the nonce;

View File

@ -58,6 +58,16 @@ public class Device extends AbstractEntity {
@Column(name = "summary_id")
private String summaryId;
public Device(final DeviceInfoReport deviceInfoReport) {
super();
if (deviceInfoReport != null) {
this.name = deviceInfoReport.getNetworkInfo().getHostname();
this.deviceInfo = deviceInfoReport;
} else {
name = "";
}
}
public String toString() {
return String.format("Device Name: %s%nStatus: %s%nSummary: %s",
name, healthStatus.getStatus(),

View File

@ -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;

View File

@ -30,7 +30,7 @@ public class ComponentClass {
private static final String TCG_COMPONENT_REGISTRY = "2.23.133.18.3.1";
private static final String SMBIOS_COMPONENT_REGISTRY = "2.23.133.18.3.3";
private static final Path JSON_PATH = FileSystems.getDefault()
.getPath("/etc", "hirs/aca", "default-properties", "component-class.json");
.getPath("/etc", "hirs", "aca", "default-properties", "component-class.json");
private static final String OTHER_STRING = "Other";
private static final String UNKNOWN_STRING = "Unknown";

View File

@ -60,5 +60,4 @@ public class AppraisalStatus {
this.message = message;
this.additionalInfo = additionalInfo;
}
}

View File

@ -41,7 +41,7 @@ import java.util.List;
@Log4j2
@NoArgsConstructor
public class AbstractRequestHandler {
public class AbstractProcessor {
@Getter
private int validDays;
@ -51,8 +51,8 @@ public class AbstractRequestHandler {
@Getter
private PolicyRepository policyRepository;
public AbstractRequestHandler(final PrivateKey privateKey,
final int validDays) {
public AbstractProcessor(final PrivateKey privateKey,
final int validDays) {
this.privateKey = privateKey;
this.validDays = validDays;
}
@ -137,7 +137,8 @@ public class AbstractRequestHandler {
if (identityClaim.hasEndorsementCredential()) {
endorsementCredential = CredentialManagementHelper.storeEndorsementCredential(
certificateRepository,
identityClaim.getEndorsementCredential().toByteArray());
identityClaim.getEndorsementCredential().toByteArray(),
identityClaim.getDv().getNw().getHostname());
} else if (ekPub != null) {
log.warn("Endorsement Cred was not in the identity claim from the client."
+ " Checking for uploads.");
@ -233,8 +234,8 @@ public class AbstractRequestHandler {
final Device device) {
IssuedAttestationCertificate issuedAc;
boolean generateCertificate = true;
PolicyRepository scp = this.getPolicyRepository();
PolicySettings policySettings = scp.findByName("Default");
PolicyRepository scp = getPolicyRepository();
PolicySettings policySettings;
Date currentDate = new Date();
int days;
try {
@ -243,6 +244,7 @@ public class AbstractRequestHandler {
derEncodedAttestationCertificate, endorsementCredential, platformCredentials);
if (scp != null) {
policySettings = scp.findByName("Default");
issuedAc = certificateRepository.findByDeviceId(device.getId());
generateCertificate = policySettings.isIssueAttestationCertificate();
@ -260,6 +262,7 @@ public class AbstractRequestHandler {
}
}
if (generateCertificate) {
attCert.setDeviceId(device.getId());
attCert.setDeviceName(device.getName());
certificateRepository.save(attCert);
}

View File

@ -27,7 +27,7 @@ import java.security.interfaces.RSAPublicKey;
import java.util.List;
@Log4j2
public class CertificateRequestHandler extends AbstractRequestHandler {
public class CertificateRequestProcessor extends AbstractProcessor {
private SupplyChainValidationService supplyChainValidationService;
private CertificateRepository certificateRepository;
@ -42,13 +42,13 @@ public class CertificateRequestHandler extends AbstractRequestHandler {
* @param validDays int for the time in which a certificate is valid.
* @param tpm2ProvisionerStateRepository db connector for provisioner state.
*/
public CertificateRequestHandler(final SupplyChainValidationService supplyChainValidationService,
final CertificateRepository certificateRepository,
final DeviceRepository deviceRepository,
final PrivateKey privateKey,
final X509Certificate acaCertificate,
final int validDays,
final TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository) {
public CertificateRequestProcessor(final SupplyChainValidationService supplyChainValidationService,
final CertificateRepository certificateRepository,
final DeviceRepository deviceRepository,
final PrivateKey privateKey,
final X509Certificate acaCertificate,
final int validDays,
final TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository) {
super(privateKey, validDays);
this.supplyChainValidationService = supplyChainValidationService;
this.certificateRepository = certificateRepository;
@ -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);

View File

@ -57,7 +57,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Log4j2
public class IdentityClaimHandler extends AbstractRequestHandler {
public class IdentityClaimProcessor extends AbstractProcessor {
private static final String PCR_QUOTE_MASK = "0,1,2,3,4,5,6,7,8,9,10,11,12,13,"
+ "14,15,16,17,18,19,20,21,22,23";
@ -78,7 +78,7 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
/**
* Constructor
*/
public IdentityClaimHandler(
public IdentityClaimProcessor(
final SupplyChainValidationService supplyChainValidationService,
final CertificateRepository certificateRepository,
final ReferenceManifestRepository referenceManifestRepository,
@ -105,7 +105,7 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
* @return an identity claim response for the specified request containing a wrapped blob
*/
public byte[] processIdentityClaimTpm2(final byte[] identityClaim) {
log.error("Identity Claim received...");
log.info("Identity Claim received...");
if (ArrayUtils.isEmpty(identityClaim)) {
log.error("Identity claim empty throwing exception.");
@ -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);
}
@ -457,8 +464,8 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
if (baseRim != null) {
// pull the base versions of the swidtag and rimel and set the
// event log hash for use during provision
SupportReferenceManifest sBaseRim = (SupportReferenceManifest) referenceManifestRepository
.findByBase64Hash(baseRim.getBase64Hash());
SupportReferenceManifest sBaseRim = referenceManifestRepository
.getSupportRimEntityById(baseRim.getAssociatedRim());
baseRim.setEventLogHash(temp.getHexDecHash());
sBaseRim.setEventLogHash(temp.getHexDecHash());
referenceManifestRepository.save(baseRim);

View File

@ -1,345 +0,0 @@
package hirs.attestationca.persist.provision;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.Device;
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.report.DeviceInfoReport;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.exceptions.IdentityProcessingException;
import hirs.attestationca.persist.provision.helper.CredentialManagementHelper;
import hirs.attestationca.persist.provision.helper.ProvisionUtils;
import hirs.attestationca.persist.service.SupplyChainValidationService;
import hirs.structs.converters.SimpleStructBuilder;
import hirs.structs.converters.StructConverter;
import hirs.structs.elements.aca.IdentityRequestEnvelope;
import hirs.structs.elements.aca.IdentityResponseEnvelope;
import hirs.structs.elements.aca.SymmetricAttestation;
import hirs.structs.elements.tpm.EncryptionScheme;
import hirs.structs.elements.tpm.IdentityProof;
import hirs.structs.elements.tpm.IdentityRequest;
import hirs.structs.elements.tpm.SymmetricKey;
import hirs.structs.elements.tpm.SymmetricKeyParams;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.SerializationUtils;
import java.io.IOException;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.LinkedList;
import java.util.List;
@Log4j2
public class IdentityRequestHandler extends AbstractRequestHandler {
/**
* Container wired ACA private key.
*/
private final PrivateKey privateKey;
private int validDays;
private StructConverter structConverter;
private CertificateRepository certificateRepository;
private DeviceRepository deviceRepository;
private SupplyChainValidationService supplyChainValidationService;
private X509Certificate acaCertificate;
/**
* Constructor.
* @param structConverter the struct converter
* @param certificateRepository
* @param deviceRepository
* @param supplyChainValidationService the supply chain service
* @param privateKey
* @param validDays int for the time in which a certificate is valid.
* @param acaCertificate object holding the x509 certificate
*/
public IdentityRequestHandler(final StructConverter structConverter,
final CertificateRepository certificateRepository,
final DeviceRepository deviceRepository,
final SupplyChainValidationService supplyChainValidationService,
final PrivateKey privateKey,
final int validDays, final X509Certificate acaCertificate) {
super(privateKey, validDays);
this.structConverter = structConverter;
this.certificateRepository = certificateRepository;
this.deviceRepository = deviceRepository;
this.supplyChainValidationService = supplyChainValidationService;
this.privateKey = privateKey;
this.acaCertificate = acaCertificate;
}
/**
* Basic implementation of the ACA processIdentityRequest method.
*
* @param identityRequest cannot be null
* @return an identity response for the specified request
*/
public byte[] processIdentityRequest(final byte[] identityRequest) {
log.info("Identity Request Received...");
if (ArrayUtils.isEmpty(identityRequest)) {
throw new IllegalArgumentException("The IdentityRequest sent by the client"
+ " cannot be null or empty.");
}
log.debug("received request to process identity request");
// translate the bytes into the challenge
IdentityRequestEnvelope challenge =
structConverter.convert(identityRequest, IdentityRequestEnvelope.class);
byte[] identityProof = unwrapIdentityRequest(structConverter.convert(challenge.getRequest(),
IdentityRequest.class));
// the decrypted symmetric blob should be in the format of an IdentityProof. Use the
// struct converter to generate it.
IdentityProof proof = structConverter.convert(identityProof, IdentityProof.class);
// convert the credential into an actual key.
log.debug("assembling public endorsement key");
PublicKey ekPublicKey = null;
// attempt to find an endorsement credential to validate
EndorsementCredential endorsementCredential = null;
// first check the identity request for the endorsement credential
byte[] ecBytesFromIdentityRequest = proof.getEndorsementCredential();
if (ArrayUtils.isNotEmpty(ecBytesFromIdentityRequest)) {
endorsementCredential = CredentialManagementHelper.storeEndorsementCredential(
this.certificateRepository, ecBytesFromIdentityRequest);
try {
BigInteger publicKeyModulus = Certificate.getPublicKeyModulus(
endorsementCredential.getX509Certificate());
if (publicKeyModulus != null) {
ekPublicKey = ProvisionUtils.assemblePublicKey(publicKeyModulus.toByteArray());
} else {
throw new IdentityProcessingException("TPM 1.2 Provisioning requires EK "
+ "Credentials to be created with RSA");
}
} catch (IOException ioEx) {
log.error("Could not retrieve the public key modulus from the EK cert");
}
} else if (ArrayUtils.isNotEmpty(challenge.getEndorsementCredentialModulus())) {
log.warn("EKC was not in the identity proof from the client. Checking for uploads.");
// Check if the EC was uploaded
ekPublicKey =
ProvisionUtils.assemblePublicKey(new String(challenge.getEndorsementCredentialModulus()));
endorsementCredential = getEndorsementCredential(ekPublicKey);
} else {
log.warn("Zero-length endorsement credential received in identity request.");
}
// get platform credential from the identity request
List<PlatformCredential> platformCredentials = new LinkedList<>();
byte[] pcBytesFromIdentityRequest = proof.getPlatformCredential();
if (ArrayUtils.isNotEmpty(pcBytesFromIdentityRequest)) {
platformCredentials.add(CredentialManagementHelper.storePlatformCredential(
this.certificateRepository, pcBytesFromIdentityRequest));
} else if (endorsementCredential != null) {
// if none in the identity request, look for uploaded platform credentials
log.warn("PC was not in the identity proof from the client. Checking for uploads.");
platformCredentials.addAll(getPlatformCredentials(endorsementCredential));
} else {
// if none in the identity request, look for uploaded platform credentials
log.warn("Zero-length platform credential received in identity request.");
}
log.debug("Processing serialized device info report structure of length {}",
challenge.getDeviceInfoReportLength());
DeviceInfoReport deviceInfoReport = (DeviceInfoReport)
SerializationUtils.deserialize(challenge.getDeviceInfoReport());
if (deviceInfoReport == null) {
log.error("Failed to deserialize Device Info Report");
throw new IdentityProcessingException("Device Info Report failed to deserialize "
+ "from Identity Request");
}
log.info("Processing Device Info Report");
// store device and device info report.
String deviceName = deviceInfoReport.getNetworkInfo().getHostname();
Device device = this.deviceRepository.findByName(deviceName);
device.setDeviceInfo(deviceInfoReport);
// perform supply chain validation. Note: It's possible that this should be done earlier
// in this method.
SupplyChainValidationSummary summary =
supplyChainValidationService.validateSupplyChain(endorsementCredential,
platformCredentials, device);
// update the validation result in the device
device.setSupplyChainValidationStatus(summary.getOverallValidationResult());
deviceRepository.save(device);
// check if supply chain validation succeeded.
// If it did not, do not provide the IdentityResponseEnvelope
if (summary.getOverallValidationResult() == AppraisalStatus.Status.PASS) {
IdentityResponseEnvelope identityResponse =
generateIdentityResponseEnvelopeAndStoreIssuedCert(challenge,
ekPublicKey, endorsementCredential, platformCredentials, device);
return structConverter.convert(identityResponse);
} else {
log.error("Supply chain validation did not succeed. Result is: "
+ summary.getOverallValidationResult());
return new byte[]{};
}
}
/**
* Given a successful supply chain validation, generate an Identity Response envelope and
* the issued certificate. The issued cert is stored in the database. The identity response
* envelope is returned, and sent back to the client using the struct converter.
* @param challenge the identity request envelope
* @param ekPublicKey the EK public key
* @param endorsementCredential the endorsement credential
* @param platformCredentials the set of platform credentials
* @param device the device associated
* @return the identity response envelope
*/
private IdentityResponseEnvelope generateIdentityResponseEnvelopeAndStoreIssuedCert(
final IdentityRequestEnvelope challenge, final PublicKey ekPublicKey,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials, final Device device) {
// decrypt the asymmetric / symmetric blobs
log.debug("unwrapping identity request");
byte[] identityProof = unwrapIdentityRequest(
structConverter.convert(challenge.getRequest(), IdentityRequest.class));
// the decrypted symmetric blob should be in the format of an IdentityProof. Use the
// struct converter to generate it.
IdentityProof proof = structConverter.convert(identityProof, IdentityProof.class);
// generate a session key and convert to byte array
log.debug("generating symmetric key for response");
SymmetricKey sessionKey = ProvisionUtils.generateSymmetricKey();
// generate the asymmetric contents for the identity response
log.debug("generating asymmetric contents for response");
byte[] asymmetricContents = ProvisionUtils.generateAsymmetricContents(
structConverter.convert(proof.getIdentityKey()),
structConverter.convert(sessionKey), ekPublicKey);
// generate the identity credential
log.debug("generating credential from identity proof");
// transform the public key struct into a public key
PublicKey publicKey = ProvisionUtils.assemblePublicKey(proof.getIdentityKey().getStorePubKey().getKey());
X509Certificate credential = generateCredential(publicKey, endorsementCredential,
platformCredentials, device.getDeviceInfo()
.getNetworkInfo()
.getIpAddress()
.getHostName(), acaCertificate);
// generate the attestation using the credential and the key for this session
log.debug("generating symmetric response");
SymmetricAttestation attestation = ProvisionUtils.generateAttestation(credential, sessionKey);
// construct the response with the both the asymmetric contents and the CA attestation
IdentityResponseEnvelope identityResponse =
new SimpleStructBuilder<>(IdentityResponseEnvelope.class)
.set("asymmetricContents", asymmetricContents)
.set("symmetricAttestation", attestation).build();
// save new attestation certificate
byte[] derEncodedAttestationCertificate = ProvisionUtils.getDerEncodedCertificate(credential);
saveAttestationCertificate(this.certificateRepository, derEncodedAttestationCertificate,
endorsementCredential, platformCredentials, device);
return identityResponse;
}
/**
* Unwraps a given identityRequest. That is to say, decrypt the asymmetric portion of a data
* structure to determine the method to decrypt the symmetric portion.
*
* @param request
* to be decrypted
* @return the decrypted symmetric portion of an identity request.
*/
private byte[] unwrapIdentityRequest(final IdentityRequest request) {
// in case the TPM did not specify the IV, it must be extracted from the symmetric blob.
// the IV will then be the the first block of the cipher text.
final byte[] iv;
SymmetricKeyParams symmetricKeyParams = request.getSymmetricAlgorithm();
if (symmetricKeyParams != null && symmetricKeyParams.getParams() != null) {
iv = symmetricKeyParams.getParams().getIv();
} else {
iv = ProvisionUtils.extractInitialValue(request);
}
// determine the encryption scheme from the algorithm
EncryptionScheme asymmetricScheme =
EncryptionScheme.fromInt(request.getAsymmetricAlgorithm().getEncryptionScheme());
// decrypt the asymmetric blob
byte[] decryptedAsymmetricBlob =
ProvisionUtils.decryptAsymmetricBlob(request.getAsymmetricBlob(), asymmetricScheme, getPrivateKey());
// construct our symmetric key structure from the decrypted asymmetric blob
SymmetricKey symmetricKey =
structConverter.convert(decryptedAsymmetricBlob, SymmetricKey.class);
byte[] decryptedSymmetricBlob =
ProvisionUtils.decryptSymmetricBlob(request.getSymmetricBlob(), symmetricKey.getKey(), iv,
"AES/CBC/PKCS5Padding");
// decrypt the symmetric blob
return decryptedSymmetricBlob;
}
/**
* Gets the Endorsement Credential from the DB given the EK public key.
* @param ekPublicKey the EK public key
* @return the Endorsement credential, if found, otherwise null
*/
private EndorsementCredential getEndorsementCredential(final PublicKey ekPublicKey) {
log.debug("Searching for endorsement credential based on public key: " + ekPublicKey);
if (ekPublicKey == null) {
throw new IllegalArgumentException("Cannot look up an EC given a null public key");
}
EndorsementCredential credential = null;
try {
credential = certificateRepository.findByPublicKeyModulusHexValue(Certificate
.getPublicKeyModulus(ekPublicKey)
.toString());
} catch (IOException ioEx) {
log.error("Could not extract public key modulus", ioEx);
}
if (credential == null) {
log.warn("Unable to find endorsement credential for public key.");
} else {
log.debug("Endorsement credential found.");
}
return credential;
}
private List<PlatformCredential> getPlatformCredentials(final EndorsementCredential ec) {
List<PlatformCredential> credentials = null;
if (ec == null) {
log.warn("Cannot look for platform credential(s). Endorsement credential was null.");
} else {
log.debug("Searching for platform credential(s) based on holder serial number: "
+ ec.getSerialNumber());
credentials = this.certificateRepository.getByHolderSerialNumber(ec.getSerialNumber());
if (credentials == null || credentials.isEmpty()) {
log.warn("No platform credential(s) found");
} else {
log.debug("Platform Credential(s) found: " + credentials.size());
}
}
return credentials;
}
}

View File

@ -27,12 +27,13 @@ public final class CredentialManagementHelper {
* it is unarchived.
* @param certificateRepository the certificate manager used for storage
* @param endorsementBytes the raw EK bytes used for parsing
* @param deviceName the host name
* @return the parsed, valid EK
* @throws IllegalArgumentException if the provided bytes are not a valid EK.
*/
public static EndorsementCredential storeEndorsementCredential(
final CertificateRepository certificateRepository,
final byte[] endorsementBytes) throws IllegalArgumentException {
final byte[] endorsementBytes, final String deviceName) throws IllegalArgumentException {
if (certificateRepository == null) {
throw new IllegalArgumentException("null certificate manager");
@ -64,6 +65,7 @@ public final class CredentialManagementHelper {
.findByCertificateHash(certificateHash);
if (existingCredential == null) {
log.info("No Endorsement Credential found with hash: " + certificateHash);
endorsementCredential.setDeviceName(deviceName);
return (EndorsementCredential) certificateRepository.save(endorsementCredential);
} else if (existingCredential.isArchived()) {
// if the EK is stored in the DB and it's archived, unarchive.

View File

@ -1,30 +1,266 @@
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.SupplyChainValidationRepository;
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 SupplyChainValidationRepository supplyChainValidationRepository;
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 supplyChainValidationRepository the scv 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 SupplyChainValidationRepository supplyChainValidationRepository,
final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository) {
this.caCredentialRepository = caCredentialRepository;
this.policyRepository = policyRepository;
this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository;
this.referenceManifestRepository = referenceManifestRepository;
this.supplyChainValidationRepository = supplyChainValidationRepository;
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...");
// Validate the Endorsement Credential
if (getPolicySettings().isEcValidationEnabled()) {
log.info("Beginning Endorsement Credential Validation...");
validations.add(ValidationService.evaluateEndorsementCredentialStatus(ec, this.caCredentialRepository, acceptExpiredCerts));
// store the device with the credential
if (ec != null) {
ec.setDeviceId(device.getId());
ec.setDeviceName(device.getDeviceInfo().getNetworkInfo().getHostname());
this.certificateRepository.save(ec);
}
}
// Validate Platform Credential signatures
if (getPolicySettings().isPcValidationEnabled()) {
log.info("Beginning Platform Credential Validation...");
// 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 = ValidationService.getCaChain(pc, caCredentialRepository);
platformScv = ValidationService.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.setEndorsementCredential(ec);
pc.setDeviceId(device.getId());
pc.setDeviceName(device.getDeviceInfo().getNetworkInfo().getHostname());
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));
}
}
}
// Validate Platform Credential attributes
if (getPolicySettings().isPcAttributeValidationEnabled()
&& pcErrorMessage.isEmpty()) {
log.info("Beginning Platform Attributes Validation...");
// 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(ValidationService.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 = ValidationService.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 = ValidationService.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()));
}
}
if (getPolicySettings().isFirmwareValidationEnabled()) {
log.info("Beginning Firmware Validation...");
// may need to associated with device to pull the correct info
// compare tpm quote with what is pulled from RIM associated file
validations.add(ValidationService.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 +268,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 = ValidationService.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(ValidationService.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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,338 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
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.certificate.CertificateAuthorityCredential;
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.validation.CertificateAttributeScvValidator;
import hirs.attestationca.persist.validation.CredentialValidator;
import hirs.attestationca.persist.validation.FirmwareScvValidator;
import hirs.utils.BouncyCastleUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.Level;
import org.bouncycastle.util.encoders.Hex;
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.Map;
import java.util.Set;
@Log4j2
public class ValidationService {
public static SupplyChainValidation evaluateEndorsementCredentialStatus(
final EndorsementCredential ec,
final CACredentialRepository caCredentialRepository,
final boolean acceptExpiredCerts) {
final SupplyChainValidation.ValidationType validationType
= SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL;
log.info("Validating endorsement credential");
if (ec == null) {
log.error("No endorsement credential to validate");
return buildValidationRecord(validationType,
AppraisalStatus.Status.FAIL, "Endorsement credential is missing",
null, Level.ERROR);
}
KeyStore ecStore = getCaChain(ec, caCredentialRepository);
AppraisalStatus result = CredentialValidator.
validateEndorsementCredential(ec, ecStore, acceptExpiredCerts);
switch (result.getAppStatus()) {
case PASS:
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,
result.getMessage(), ec, Level.INFO);
case FAIL:
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), ec, Level.WARN);
case ERROR:
default:
return buildValidationRecord(validationType, AppraisalStatus.Status.ERROR,
result.getMessage(), ec, Level.ERROR);
}
}
public static SupplyChainValidation evaluatePlatformCredentialStatus(
final PlatformCredential pc,
final KeyStore trustedCertificateAuthority, final boolean acceptExpiredCerts) {
final SupplyChainValidation.ValidationType validationType
= SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL;
if (pc == null) {
log.error("No platform credential to validate");
return buildValidationRecord(validationType,
AppraisalStatus.Status.FAIL, "Empty Platform credential", null, Level.ERROR);
}
log.info("Validating Platform Credential");
AppraisalStatus result = CredentialValidator.validatePlatformCredential(pc,
trustedCertificateAuthority, acceptExpiredCerts);
switch (result.getAppStatus()) {
case PASS:
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,
result.getMessage(), pc, Level.INFO);
case FAIL:
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), pc, Level.WARN);
case ERROR:
default:
return buildValidationRecord(validationType, AppraisalStatus.Status.ERROR,
result.getMessage(), pc, Level.ERROR);
}
}
public static SupplyChainValidation evaluatePCAttributesStatus(
final PlatformCredential pc, final DeviceInfoReport deviceInfoReport,
final EndorsementCredential ec,
final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository) {
final SupplyChainValidation.ValidationType validationType
= SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES;
if (pc == null) {
log.error("No platform credential to validate");
return buildValidationRecord(validationType,
AppraisalStatus.Status.FAIL, "Platform credential is missing",
null, Level.ERROR);
}
log.info("Validating platform credential attributes");
AppraisalStatus result = CredentialValidator.
validatePlatformCredentialAttributes(pc, deviceInfoReport, ec);
switch (result.getAppStatus()) {
case PASS:
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,
result.getMessage(), pc, Level.INFO);
case FAIL:
if (!result.getAdditionalInfo().isEmpty()) {
pc.setComponentFailures(result.getAdditionalInfo());
pc.setComponentFailureMessage(result.getMessage());
certificateRepository.save(pc);
for (ComponentResult componentResult
: CertificateAttributeScvValidator.getComponentResultList()) {
componentResultRepository.save(componentResult);
}
}
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), pc, Level.WARN);
case ERROR:
default:
return buildValidationRecord(validationType, AppraisalStatus.Status.ERROR,
result.getMessage(), pc, Level.ERROR);
}
}
public static SupplyChainValidation evaluateDeltaAttributesStatus(
final PlatformCredential delta,
final DeviceInfoReport deviceInfoReport,
final PlatformCredential base,
final Map<PlatformCredential, SupplyChainValidation> deltaMapping,
final CertificateRepository certificateRepository) {
final SupplyChainValidation.ValidationType validationType
= SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES;
if (delta == null) {
log.error("No delta certificate to validate");
return buildValidationRecord(validationType,
AppraisalStatus.Status.FAIL, "Delta platform certificate is missing",
null, Level.ERROR);
}
log.info("Validating delta platform certificate attributes");
AppraisalStatus result = CertificateAttributeScvValidator.
validateDeltaPlatformCredentialAttributes(delta, deviceInfoReport,
base, deltaMapping);
switch (result.getAppStatus()) {
case PASS:
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,
result.getMessage(), delta, Level.INFO);
case FAIL:
if (!result.getAdditionalInfo().isEmpty()) {
base.setComponentFailures(result.getAdditionalInfo());
base.setComponentFailureMessage(result.getMessage());
certificateRepository.save(base);
}
// we are adding things to componentFailures
certificateRepository.save(delta);
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), delta, Level.WARN);
case ERROR:
default:
return buildValidationRecord(validationType, AppraisalStatus.Status.ERROR,
result.getMessage(), delta, Level.ERROR);
}
}
public static SupplyChainValidation evaluateFirmwareStatus(
final Device device,
final PolicySettings policySettings, final ReferenceManifestRepository rimRepo,
final ReferenceDigestValueRepository rdvRepo,
final CACredentialRepository caRepo) {
final SupplyChainValidation.ValidationType validationType
= SupplyChainValidation.ValidationType.FIRMWARE;
AppraisalStatus result = FirmwareScvValidator.validateFirmware(device, policySettings,
rimRepo, rdvRepo, caRepo);
Level logLevel;
switch (result.getAppStatus()) {
case PASS:
logLevel = Level.INFO;
break;
case FAIL:
logLevel = Level.WARN;
break;
case ERROR:
default:
logLevel = Level.ERROR;
}
return buildValidationRecord(validationType, result.getAppStatus(),
result.getMessage(), null, logLevel);
}
/**
* 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
*/
public static 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 certificate the credential whose CA chain should be retrieved
* @param caCredentialRepository db service to get CA Certs
* @return A keystore containing all relevant CA credentials to the given
* certificate's organization or null if the keystore can't be assembled
*/
public static KeyStore getCaChain(final Certificate certificate,
final CACredentialRepository caCredentialRepository) {
KeyStore caKeyStore = null;
try {
caKeyStore = caCertSetToKeystore(getCaChainRec(certificate, Collections.emptySet(),
caCredentialRepository));
} 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
*/
public static Set<CertificateAuthorityCredential> getCaChainRec(
final Certificate credential,
final Set<String> previouslyQueriedSubjects,
final CACredentialRepository caCredentialRepository) {
CertificateAuthorityCredential skiCA = null;
List<CertificateAuthorityCredential> certAuthsWithMatchingIssuer = new LinkedList<>();
if (credential.getAuthorityKeyIdentifier() != null
&& !credential.getAuthorityKeyIdentifier().isEmpty()) {
byte[] bytes = Hex.decode(credential.getAuthorityKeyIdentifier());
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, caCredentialRepository));
}
}
return caCreds;
}
public static 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;
}
}

View File

@ -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;

View File

@ -1,19 +1,92 @@
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";
return new AppraisalStatus(FAIL, message);
}
if (trustStore == null) {
message = baseErrorMessage + "a trust store";
return new AppraisalStatus(FAIL, message);
}
boolean keyInStore = false;
try {
keyInStore = trustStore.size() < 1;
} catch (KeyStoreException ksEx) {
log.error(ksEx.getMessage());
}
if (keyInStore) {
message = baseErrorMessage + "keys in the trust store";
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";
return new AppraisalStatus(ERROR, message + " " + e.getMessage());
} catch (SupplyChainValidatorException e) {
message = "An error occurred indicating the credential is not valid";
return new AppraisalStatus(ERROR, message + " " + e.getMessage());
} catch (CertificateExpiredException e) {
message = "The endorsement credential is expired";
return new AppraisalStatus(FAIL, message + " " + e.getMessage());
} catch (CertificateNotYetValidException e) {
message = "The endorsement credential is not yet valid";
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 +95,106 @@ 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";
return new AppraisalStatus(FAIL, message);
}
try {
if (trustStore == null || trustStore.size() == 0) {
message = baseErrorMessage + "an Issuer Cert in the Trust Store";
return new AppraisalStatus(FAIL, message);
}
} catch (KeyStoreException e) {
message = baseErrorMessage + "an initialized trust store";
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.debug(message);
return new AppraisalStatus(FAIL, message);
}
// verify cert against truststore
try {
certVerifyMsg = verifyCertificate(attributeCert, trustStore);
if (certVerifyMsg.isEmpty()) {
message = PLATFORM_VALID;
log.debug(message);
return new AppraisalStatus(PASS, message);
} else {
message = String.format("Platform credential failed verification%n%s",
certVerifyMsg);
log.debug(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";
return new AppraisalStatus(FAIL, message);
}
if (deviceInfoReport == null) {
message = baseErrorMessage + "a device info report";
return new AppraisalStatus(FAIL, message);
}
if (endorsementCredential == null) {
message = baseErrorMessage + "an endorsement credential";
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";
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);
}
}

View File

@ -0,0 +1,254 @@
package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
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.enums.AppraisalStatus;
import hirs.attestationca.persist.service.ValidationService;
import hirs.utils.SwidResource;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import lombok.extern.log4j.Log4j2;
import java.io.IOException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
@Log4j2
public class FirmwareScvValidator extends SupplyChainCredentialValidator {
private static PcrValidator pcrValidator;
@SuppressWarnings("methodlength")
public static AppraisalStatus validateFirmware(
final Device device, final PolicySettings policySettings,
final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository,
final CACredentialRepository caCredentialRepository) {
boolean passed = true;
String[] baseline = new String[Integer.SIZE];
AppraisalStatus fwStatus = null;
String hostName = device.getDeviceInfo().getNetworkInfo().getHostname();
String manufacturer = device.getDeviceInfo()
.getHardwareInfo().getManufacturer();
ReferenceManifest validationObject;
List<BaseReferenceManifest> baseReferenceManifests = null;
BaseReferenceManifest baseReferenceManifest = null;
ReferenceManifest supportReferenceManifest = null;
EventLogMeasurements measurement = null;
baseReferenceManifests = referenceManifestRepository.findAllBaseRims();
for (BaseReferenceManifest bRim : baseReferenceManifests) {
if (bRim.getDeviceName().equals(hostName)
&& !bRim.isSwidSupplemental() && !bRim.isSwidPatch()) {
baseReferenceManifest = bRim;
}
}
String failedString = "";
if (baseReferenceManifest == null) {
failedString = "Base Reference Integrity Manifest\n";
passed = false;
} else {
measurement = (EventLogMeasurements) referenceManifestRepository.findByHexDecHash(
baseReferenceManifest.getEventLogHash());
if (measurement == null) {
measurement = referenceManifestRepository.byMeasurementDeviceName(
baseReferenceManifest.getDeviceName());
}
}
if (measurement == null) {
failedString += "Bios measurement";
passed = false;
}
validationObject = measurement;
if (passed) {
List<SwidResource> resources =
((BaseReferenceManifest) baseReferenceManifest).getFileResources();
fwStatus = new AppraisalStatus(PASS,
SupplyChainCredentialValidator.FIRMWARE_VALID);
// verify signatures
ReferenceManifestValidator referenceManifestValidator =
new ReferenceManifestValidator();
referenceManifestValidator.setRim(baseReferenceManifest);
//Validate signing cert
List<CertificateAuthorityCredential> allCerts = caCredentialRepository.findAll();
CertificateAuthorityCredential signingCert = null;
for (CertificateAuthorityCredential cert : allCerts) {
signingCert = cert;
KeyStore keyStore = ValidationService.getCaChain(signingCert,
caCredentialRepository);
if (referenceManifestValidator.validateXmlSignature(signingCert)) {
try {
if (!SupplyChainCredentialValidator.verifyCertificate(
signingCert.getX509Certificate(), keyStore)) {
passed = false;
fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: invalid certificate path.");
validationObject = baseReferenceManifest;
}
} catch (IOException ioEx) {
log.error("Error getting X509 cert from manager: " + ioEx.getMessage());
} catch (SupplyChainValidatorException scvEx) {
log.error("Error validating cert against keystore: " + scvEx.getMessage());
fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: invalid certificate path.");
}
break;
}
}
for (SwidResource swidRes : resources) {
supportReferenceManifest = referenceManifestRepository.findByHexDecHash(
swidRes.getHashValue());
if (supportReferenceManifest != null) {
// Removed the filename check from this if statement
referenceManifestValidator.validateSupportRimHash(
supportReferenceManifest.getRimBytes(), swidRes.getHashValue());
}
}
if (passed && signingCert == null) {
passed = false;
fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: signing cert not found.");
}
if (passed && supportReferenceManifest == null) {
fwStatus = new AppraisalStatus(FAIL,
"Support Reference Integrity Manifest can not be found");
passed = false;
}
if (passed && !referenceManifestValidator.isSignatureValid()) {
passed = false;
fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: Signature validation "
+ "failed for Base RIM.");
}
if (passed && !referenceManifestValidator.isSupportRimValid()) {
passed = false;
fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: Hash validation "
+ "failed for Support RIM.");
}
if (passed) {
TCGEventLog logProcessor;
try {
logProcessor = new TCGEventLog(supportReferenceManifest.getRimBytes());
baseline = logProcessor.getExpectedPCRValues();
} catch (CertificateException cEx) {
log.error(cEx);
} catch (NoSuchAlgorithmException noSaEx) {
log.error(noSaEx);
} catch (IOException ioEx) {
log.error(ioEx);
}
// part 1 of firmware validation check: PCR baseline match
pcrValidator = new PcrValidator(baseline);
if (baseline.length > 0) {
String pcrContent = "";
pcrContent = new String(device.getDeviceInfo().getTpmInfo().getPcrValues());
if (pcrContent.isEmpty()) {
fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: Client did not "
+ "provide pcr values.");
log.warn(String.format(
"Firmware validation failed: Client (%s) did not "
+ "provide pcr values.", device.getName()));
} else {
// we have a full set of PCR values
//int algorithmLength = baseline[0].length();
//String[] storedPcrs = buildStoredPcrs(pcrContent, algorithmLength);
//pcrPolicy.validatePcrs(storedPcrs);
// part 2 of firmware validation check: bios measurements
// vs baseline tcg event log
// find the measurement
TCGEventLog tcgMeasurementLog;
LinkedList<TpmPcrEvent> tpmPcrEvents = new LinkedList<>();
List<ReferenceDigestValue> eventValue;
HashMap<String, ReferenceDigestValue> eventValueMap = new HashMap<>();
try {
if (measurement.getDeviceName().equals(hostName)) {
tcgMeasurementLog = new TCGEventLog(measurement.getRimBytes());
eventValue = referenceDigestValueRepository
.findValuesByBaseRimId(baseReferenceManifest.getId());
for (ReferenceDigestValue rdv : eventValue) {
eventValueMap.put(rdv.getDigestValue(), rdv);
}
tpmPcrEvents.addAll(pcrValidator.validateTpmEvents(
tcgMeasurementLog, eventValueMap, policySettings));
}
} catch (CertificateException cEx) {
log.error(cEx);
} catch (NoSuchAlgorithmException noSaEx) {
log.error(noSaEx);
} catch (IOException ioEx) {
log.error(ioEx);
}
if (!tpmPcrEvents.isEmpty()) {
StringBuilder sb = new StringBuilder();
validationObject = measurement;
sb.append(String.format("%d digest(s) were not found:%n",
tpmPcrEvents.size()));
for (TpmPcrEvent tpe : tpmPcrEvents) {
sb.append(String.format("PCR Index %d - %s%n",
tpe.getPcrIndex(),
tpe.getEventTypeStr()));
}
if (fwStatus.getAppStatus().equals(FAIL)) {
fwStatus = new AppraisalStatus(FAIL, String.format("%s%n%s",
fwStatus.getMessage(), sb.toString()));
} else {
fwStatus = new AppraisalStatus(FAIL, sb.toString());
}
}
}
} else {
fwStatus = new AppraisalStatus(FAIL, "The RIM baseline could not be found.");
}
}
EventLogMeasurements eventLog = measurement;
eventLog.setOverallValidationResult(fwStatus.getAppStatus());
referenceManifestRepository.save(eventLog);
} else {
fwStatus = new AppraisalStatus(FAIL, String.format("Firmware Validation failed: "
+ "%s for %s can not be found", failedString, hostName));
if (measurement != null) {
measurement.setOverallValidationResult(fwStatus.getAppStatus());
referenceManifestRepository.save(measurement);
}
}
return fwStatus;
}
}

View File

@ -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;
}
}

View File

@ -1,23 +1,46 @@
package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
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 com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
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.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 +62,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;
}
}
}

View File

@ -97,16 +97,16 @@ ospackage {
}
// Post Install
postInstall 'sh /opt/hirs/aca/scripts/aca/aca_setup.sh -u'
postInstall 'bash /opt/hirs/aca/scripts/aca/aca_setup.sh -u'
// add chrontab to run ACA at boot
postInstall 'echo "@reboot root /opt/hirs/aca/scripts/aca/aca_bootRun.sh -w" >> /etc/crontab'
// run ACA after install
postInstall '/opt/hirs/aca/scripts/aca/aca_bootRun.sh -w &'
postInstall 'chmod +x /opt/hirs/aca/scripts/aca/*'
postInstall 'sh /opt/hirs/aca/scripts/aca/check_for_aca.sh'
postInstall 'bash /opt/hirs/aca/scripts/aca/check_for_aca.sh'
// Uninstall
preUninstall 'sh /opt/hirs/aca/scripts/aca/aca_remove_setup.sh'
preUninstall 'bash /opt/hirs/aca/scripts/aca/aca_remove_setup.sh'
postUninstall 'rm -rf /etc/hirs'
buildRpm {
@ -114,6 +114,7 @@ ospackage {
}
buildDeb {
packageName = 'hirs-attestationca'
arch = 'amd64'
}
}

View File

@ -52,7 +52,7 @@ import java.util.Properties;
@PropertySource(value = "classpath:hibernate.properties"),
// detects if file exists, if not, ignore errors
@PropertySource(value = "file:/etc/hirs/aca/application.properties",
@PropertySource(value = "file:/etc/hirs/aca/aca.properties",
ignoreResourceNotFound = true)
})
@ComponentScan({"hirs.attestationca.portal", "hirs.attestationca.portal.page.controllers", "hirs.attestationca.persist", "hirs.attestationca.persist.entity", "hirs.attestationca.persist.service"})

View File

@ -234,16 +234,16 @@ public class CertificatePageController extends PageController<NoPageParams> {
// Add the EndorsementCredential for each PlatformCredential based on the
// serial number. (pc.HolderSerialNumber = ec.SerialNumber)
if (certificateType.equals(PLATFORMCREDENTIAL)) {
// records = OrderedListQueryDataTableAdapter.getOrderedList(
// getCertificateClass(certificateType), platformCertificateRepository,
// input, orderColumnName, criteriaModifier);
FilteredRecordsList<PlatformCredential> records = new FilteredRecordsList<>();
org.springframework.data.domain.Page<PlatformCredential> pagedResult = this.platformCertificateRepository.findAll(paging);
if (pagedResult.hasContent()) {
records.addAll(pagedResult.getContent());
records.setRecordsTotal(pagedResult.getContent().size());
} else {
records.setRecordsTotal(input.getLength());
}
records.setRecordsTotal(input.getLength());
records.setRecordsFiltered(platformCertificateRepository.count());
EndorsementCredential associatedEC;
@ -267,31 +267,31 @@ public class CertificatePageController extends PageController<NoPageParams> {
log.debug("Returning list of size: " + records.size());
return new DataTableResponse<>(records, input);
} else if (certificateType.equals(ENDORSEMENTCREDENTIAL)) {
// records = OrderedListQueryDataTableAdapter.getOrderedList(
// getCertificateClass(certificateType), endorsementCredentialRepository,
// input, orderColumnName, criteriaModifier);
FilteredRecordsList<EndorsementCredential> records = new FilteredRecordsList<>();
org.springframework.data.domain.Page<EndorsementCredential> pagedResult = this.endorsementCredentialRepository.findAll(paging);
if (pagedResult.hasContent()) {
records.addAll(pagedResult.getContent());
records.setRecordsTotal(pagedResult.getContent().size());
} else {
records.setRecordsTotal(input.getLength());
}
records.setRecordsTotal(input.getLength());
records.setRecordsFiltered(endorsementCredentialRepository.count());
log.debug("Returning list of size: " + records.size());
return new DataTableResponse<>(records, input);
} else if (certificateType.equals(TRUSTCHAIN)) {
// records = OrderedListQueryDataTableAdapter.getOrderedList(
// getCertificateClass(certificateType), caCredentialRepository,
// input, orderColumnName, criteriaModifier);
FilteredRecordsList<CertificateAuthorityCredential> records = new FilteredRecordsList<>();
org.springframework.data.domain.Page<CertificateAuthorityCredential> pagedResult = this.caCredentialRepository.findAll(paging);
if (pagedResult.hasContent()) {
records.addAll(pagedResult.getContent());
records.setRecordsTotal(pagedResult.getContent().size());
} else {
records.setRecordsTotal(input.getLength());
}
records.setRecordsTotal(input.getLength());
records.setRecordsFiltered(caCredentialRepository.count());
log.debug("Returning list of size: " + records.size());
@ -299,10 +299,14 @@ public class CertificatePageController extends PageController<NoPageParams> {
} else if (certificateType.equals(ISSUEDCERTIFICATES)) {
FilteredRecordsList<IssuedAttestationCertificate> records = new FilteredRecordsList<>();
org.springframework.data.domain.Page<IssuedAttestationCertificate> pagedResult = this.issuedCertificateRepository.findAll(paging);
if (pagedResult.hasContent()) {
records.addAll(pagedResult.getContent());
records.setRecordsTotal(pagedResult.getContent().size());
} else {
records.setRecordsTotal(input.getLength());
}
records.setRecordsTotal(input.getLength());
records.setRecordsFiltered(issuedCertificateRepository.count());
log.debug("Returning list of size: " + records.size());
@ -389,14 +393,14 @@ public class CertificatePageController extends PageController<NoPageParams> {
for (PlatformCredential pc : sharedCertificates) {
if (!pc.isPlatformBase()) {
pc.archive();
certificateRepository.delete(pc);
certificateRepository.save(pc);
}
}
}
}
certificate.archive();
certificateRepository.delete(certificate);
certificateRepository.save(certificate);
String deleteCompletedMessage = "Certificate successfully deleted";
messages.addInfo(deleteCompletedMessage);
@ -832,11 +836,11 @@ public class CertificatePageController extends PageController<NoPageParams> {
log.error(failMessage, dEx);
messages.addError(failMessage + dEx.getMessage());
return null;
} catch (IllegalArgumentException e) {
} catch (IllegalArgumentException iaEx) {
final String failMessage = String.format(
"Certificate format not recognized(%s): ", fileName);
log.error(failMessage, e);
messages.addError(failMessage + e.getMessage());
log.error(failMessage, iaEx);
messages.addError(failMessage + iaEx.getMessage());
return null;
}
}
@ -864,11 +868,11 @@ public class CertificatePageController extends PageController<NoPageParams> {
existingCertificate = getCertificateByHash(
certificateType,
certificate.getCertificateHash());
} catch (DBServiceException e) {
} catch (DBServiceException dbsEx) {
final String failMessage = "Querying for existing certificate failed ("
+ fileName + "): ";
messages.addError(failMessage + e.getMessage());
log.error(failMessage, e);
messages.addError(failMessage + dbsEx.getMessage());
log.error(failMessage, dbsEx);
return;
}
@ -924,11 +928,11 @@ public class CertificatePageController extends PageController<NoPageParams> {
log.info(successMsg);
return;
}
} catch (DBServiceException e) {
} catch (DBServiceException dbsEx) {
final String failMessage = String.format("Storing new certificate failed (%s): ",
fileName);
messages.addError(failMessage + e.getMessage());
log.error(failMessage, e);
messages.addError(failMessage + dbsEx.getMessage());
log.error(failMessage, dbsEx);
return;
}
@ -946,12 +950,12 @@ public class CertificatePageController extends PageController<NoPageParams> {
log.info(successMsg);
return;
}
} catch (DBServiceException e) {
} catch (DBServiceException dbsEx) {
final String failMessage = String.format("Found an identical"
+ " pre-existing certificate in the "
+ "archive, but failed to unarchive it (%s): ", fileName);
messages.addError(failMessage + e.getMessage());
log.error(failMessage, e);
messages.addError(failMessage + dbsEx.getMessage());
log.error(failMessage, dbsEx);
return;
}

View File

@ -84,10 +84,6 @@ public class DevicePageController extends PageController<NoPageParams> {
// get all the devices
FilteredRecordsList<Device> deviceList = new FilteredRecordsList<>();
// OrderedListQueryDataTableAdapter.getOrderedList(
// Device.class,
// deviceRepository,
// input, orderColumnName);
int currentPage = input.getStart() / input.getLength();
Pageable paging = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName));
@ -95,8 +91,10 @@ public class DevicePageController extends PageController<NoPageParams> {
if (pagedResult.hasContent()) {
deviceList.addAll(pagedResult.getContent());
deviceList.setRecordsTotal(pagedResult.getContent().size());
} else {
deviceList.setRecordsTotal(input.getLength());
}
deviceList.setRecordsTotal(input.getLength());
deviceList.setRecordsFiltered(deviceRepository.count());
FilteredRecordsList<HashMap<String, Object>> records
@ -131,10 +129,11 @@ public class DevicePageController extends PageController<NoPageParams> {
issuedCertificateList.addAll(issuedCertificateRepository.findByDeviceId(id));
}
HashMap<String, List<Object>> certificatePropertyMap;
// loop all the devices
for (Device device : deviceList) {
// hashmap containing the list of certificates based on the certificate type
HashMap<String, List<Object>> certificatePropertyMap = new HashMap<>();
certificatePropertyMap = new HashMap<>();
deviceCertMap.put("device", device);
String deviceName;
@ -179,8 +178,7 @@ public class DevicePageController extends PageController<NoPageParams> {
}
for (IssuedAttestationCertificate ic : issuedCertificateList) {
deviceName = deviceRepository.findById(ic.getDeviceId()).get().getName();
deviceName = ic.getDeviceName();
// set the certificate if it's the same ID
if (device.getName().equals(deviceName)) {
String certificateId = IssuedAttestationCertificate.class.getSimpleName();

View File

@ -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.ValidationService;
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;
@ -31,6 +32,7 @@ import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
@ -52,6 +54,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 +64,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 +106,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 +137,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 +146,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 +155,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 +181,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 +190,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<>();
@ -256,8 +267,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
baseRim.setAssociatedRim(support.getId());
}
} else {
support = (SupportReferenceManifest) referenceManifestRepository
.getReferenceById(baseRim.getAssociatedRim());
support = referenceManifestRepository
.getSupportRimEntityById(baseRim.getAssociatedRim());
}
// going to have to pull the filename and grab that from the DB
// to get the id to make the link
@ -288,9 +299,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 = ValidationService.getCaChain(cert, caCertificateRepository);
if (RIM_VALIDATOR.validateXmlSignature(cert)) {
try {
if (SupplyChainCredentialValidator.verifyCertificate(
@ -298,21 +307,23 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
data.replace("signatureValid", true);
break;
}
} catch (SupplyChainValidatorException e) {
log.error("Error verifying cert chain: " + e.getMessage());
} catch (SupplyChainValidatorException scvEx) {
log.error("Error verifying cert chain: " + scvEx.getMessage());
}
}
}
data.put("skID", RIM_VALIDATOR.getSubjectKeyIdentifier());
try {
for (CertificateAuthorityCredential cert : certificates) {
if (Arrays.equals(cert.getEncodedPublicKey(),
RIM_VALIDATOR.getPublicKey().getEncoded())) {
data.put("issuerID", cert.getId().toString());
if (RIM_VALIDATOR.getPublicKey() != null) {
for (CertificateAuthorityCredential cert : certificates) {
if (Arrays.equals(cert.getEncodedPublicKey(),
RIM_VALIDATOR.getPublicKey().getEncoded())) {
data.put("issuerID", cert.getId().toString());
}
}
}
} catch (NullPointerException e) {
log.warn("Unable to link signing certificate: " + e.getMessage());
} catch (NullPointerException npEx) {
log.warn("Unable to link signing certificate: " + npEx.getMessage());
}
return data;
}

View File

@ -1,18 +1,15 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages;
@ -20,13 +17,9 @@ import hirs.attestationca.portal.page.params.NoPageParams;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.extern.log4j.Log4j2;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@ -45,7 +38,6 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;
import java.io.IOException;
import java.lang.ref.Reference;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
@ -123,36 +115,27 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
String orderColumnName = input.getOrderColumnName();
log.info("Ordering on column: " + orderColumnName);
// check that the alert is not archived and that it is in the specified report
CriteriaModifier criteriaModifier = new CriteriaModifier() {
@Override
public void modify(final CriteriaQuery criteriaQuery) {
Session session = entityManager.unwrap(Session.class);
CriteriaBuilder cb = session.getCriteriaBuilder();
Root<ReferenceManifest> rimRoot = criteriaQuery.from(Reference.class);
criteriaQuery.select(rimRoot).distinct(true).where(cb.isNull(rimRoot.get(Certificate.ARCHIVE_FIELD)));
}
};
log.info("Querying with the following dataTableInput: " + input.toString());
FilteredRecordsList<ReferenceManifest> records = new FilteredRecordsList<>();
int currentPage = input.getStart() / input.getLength();
Pageable paging = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName));
org.springframework.data.domain.Page<ReferenceManifest> pagedResult = referenceManifestRepository.findAll(paging);
int rimCount = 0;
if (pagedResult.hasContent()) {
records.addAll(pagedResult.getContent());
for (ReferenceManifest manifest : pagedResult.getContent()) {
if (!manifest.getRimType().equals(ReferenceManifest.MEASUREMENT_RIM)) {
records.add(manifest);
rimCount++;
}
}
records.setRecordsTotal(rimCount);
} else {
records.setRecordsTotal(input.getLength());
}
records.setRecordsTotal(input.getLength());
records.setRecordsFiltered(referenceManifestRepository.count());
// FilteredRecordsList<ReferenceManifest> records
// = OrderedListQueryDataTableAdapter.getOrderedList(
// ReferenceManifest.class,
// this.referenceManifestRepository,
// input, orderColumnName, criteriaModifier);
log.debug("Returning list of size: " + records.size());
return new DataTableResponse<>(records, input);

View File

@ -1,35 +0,0 @@
package hirs.attestationca.portal.page.controllers;
/**
* Restful implementation of the {@link }.
* Exposes the ACA methods as REST endpoints.
*/
//@RestController
//@RequestMapping("/")
public class RestfulAttestationCertificateAuthority {
// private final ReferenceManifestRepository referenceManifestRepository;
// private final ReferenceDigestValueRepository referenceDigestValueRepository;
//
// @Autowired
// public RestfulAttestationCertificateAuthority(
// final ReferenceManifestRepository referenceManifestRepository,
// final ReferenceDigestValueRepository referenceDigestValueRepository) {
//
// this.referenceManifestRepository = referenceManifestRepository;
// this.referenceDigestValueRepository = referenceDigestValueRepository;
//
// }
//
//
// @ResponseBody
// @RequestMapping(value = "/upload-swidtag", method = RequestMethod.POST, consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
// public byte[] uploadSwidtag(@RequestBody final byte[] request) {
// return null;
// }
//
// @ResponseBody
// @RequestMapping(value = "/upload-rimel", method = RequestMethod.POST, consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
// public byte[] uploadRimel(@RequestBody final byte[] request) {
// return null;
// }
}

View File

@ -116,15 +116,12 @@ public class RimDatabasePageController extends PageController<NoPageParams> {
if (pagedResult.hasContent()) {
referenceDigestValues.addAll(pagedResult.getContent());
referenceDigestValues.setRecordsTotal(pagedResult.getContent().size());
} else {
referenceDigestValues.setRecordsTotal(input.getLength());
}
referenceDigestValues.setRecordsTotal(input.getLength());
referenceDigestValues.setRecordsFiltered(referenceDigestValueRepository.count());
// FilteredRecordsList<ReferenceDigestValue> referenceDigestValues =
// OrderedListQueryDataTableAdapter.getOrderedList(
// referenceDigestValueRepository,
// input, orderColumnName, criteriaModifier, entityManager);
// might be able to get rid of this, maybe right a query that looks for not updated
SupportReferenceManifest support;
for (ReferenceDigestValue rdv : referenceDigestValues) {

View File

@ -2,13 +2,11 @@ package hirs.attestationca.portal.page.controllers;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.manager.PlatformCertificateRepository;
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.SupplyChainValidationSummary;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
@ -16,18 +14,13 @@ import hirs.attestationca.persist.entity.userdefined.certificate.attributes.Comp
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@ -43,7 +36,6 @@ import org.springframework.web.servlet.ModelAndView;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.ref.Reference;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -52,7 +44,6 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -128,20 +119,6 @@ public class ValidationReportsPageController extends PageController<NoPageParams
String orderColumnName = input.getOrderColumnName();
log.debug("Ordering on column: " + orderColumnName);
// define an alias so the composite object, device, can be used by the
// datatables / query. This is necessary so the device.name property can
// be used.
CriteriaModifier criteriaModifier = new CriteriaModifier() {
@Override
public void modify(final CriteriaQuery criteriaQuery) {
Session session = entityManager.unwrap(Session.class);
CriteriaBuilder cb = session.getCriteriaBuilder();
Root<Certificate> scvRoot = criteriaQuery.from(Reference.class);
criteriaQuery.select(scvRoot).distinct(true).where(cb.isNull(scvRoot.get(Certificate.ARCHIVE_FIELD)));
}
};
FilteredRecordsList<SupplyChainValidationSummary> records = new FilteredRecordsList<>();
int currentPage = input.getStart() / input.getLength();
Pageable paging = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName));
@ -149,15 +126,12 @@ public class ValidationReportsPageController extends PageController<NoPageParams
if (pagedResult.hasContent()) {
records.addAll(pagedResult.getContent());
records.setRecordsTotal(pagedResult.getContent().size());
} else {
records.setRecordsTotal(input.getLength());
}
records.setRecordsTotal(input.getLength());
records.setRecordsFiltered(supplyChainValidatorSummaryRepository.count());
// FilteredRecordsList<SupplyChainValidationSummary> records =
// OrderedListQueryDataTableAdapter.getOrderedList(
// SupplyChainValidationSummary.class,
// supplyChainValidatorSummaryRepository, input, orderColumnName,
// criteriaModifier);
records.setRecordsFiltered(supplyChainValidatorSummaryRepository.count());
return new DataTableResponse<>(records, input);
}

View File

@ -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;
@ -19,6 +20,7 @@ import org.bouncycastle.util.encoders.Hex;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@ -148,15 +150,14 @@ public final class CertificateStringMapBuilder {
final Certificate certificate,
final CertificateRepository certificateRepository,
final CACredentialRepository caCredentialRepository) {
List<CertificateAuthorityCredential> issuerCertificates = new LinkedList<>();
List<CertificateAuthorityCredential> issuerCertificates = new ArrayList<>();
CertificateAuthorityCredential skiCA = null;
String issuerResult;
//Check if there is a subject organization
if (certificate.getAuthorityKeyIdentifier() != null
&& !certificate.getAuthorityKeyIdentifier().isEmpty()) {
byte[] bytes = Hex.decode(certificate.getAuthorityKeyIdentifier());
skiCA = caCredentialRepository.findBySubjectKeyIdentifier(bytes);
skiCA = caCredentialRepository.findBySubjectKeyIdString(certificate.getAuthorityKeyIdentifier());
} else {
log.error(String.format("Certificate (%s) for %s has no authority key identifier.",
certificate.getClass().toString(), certificate.getSubject()));
@ -184,7 +185,7 @@ public final class CertificateStringMapBuilder {
if (issuerResult.isEmpty()) {
//Check if it's root certificate
if (BouncyCastleUtils.x500NameCompare(issuerCert.getIssuerSorted(),
issuerCert.getSubject())) {
issuerCert.getSubjectSorted())) {
return null;
}
return containsAllChain(issuerCert, certificateRepository, caCredentialRepository);

View File

@ -52,13 +52,7 @@
data: 'deviceName',
render: function (data, type, full, meta) {
// if there's a device, display its name, otherwise
// display nothing
if (full.device) {
// TODO render a link to a device details page,
// passing the device.id
return full.deviceName;
}
return '';
return full.deviceName;
}
},
{data: 'issuer'},

View File

@ -1,3 +1,15 @@
<div class="container">
Page Not Found! <a href="/devices">Devices</a>
</div>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%-- JSP TAGS --%>
<%@taglib prefix="c" uri="jakarta.tags.core" %>
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
<%-- CONTENT --%>
<my:page>
<jsp:attribute name="pageHeaderTitle">Error - 404</jsp:attribute>
<jsp:body>
<!--<div> Exception Message: <c:out value="${exception}"</c:out></div>
<div> from URL -> <span th:text="${url}"</span></div>-->
</jsp:body>
</my:page>

View File

@ -10,12 +10,16 @@
<jsp:body>
<h3 class="content-subhead" id="alerttype">Documentation</h3>
<!--
<ul>
<c:forEach items="${docs}" var="doc">
<li><a href="${baseURL}/docs/${doc.name}">${doc.name}</a></li>
</c:forEach>
</ul>
-->
<p>For more documentation on the project, you may visit the wiki section of our code repository.</p>
<p>
For more documentation on the project, you may visit the wiki section of our <a href="https://github.com/nsacyber/HIRS/wiki">code repository</a>.
</p>
</jsp:body>
</my:page>

View File

@ -48,12 +48,7 @@
render: function (data, type, full, meta) {
// if there's a device, display its name, otherwise
// display nothing
if (full.device) {
// TODO render a link to a device details page,
// passing the device.id
return full.deviceName;
}
return '';
return full.deviceName;
}
},
{data: 'issuer'},

View File

@ -57,13 +57,7 @@
data: 'deviceName',
render: function (data, type, full, meta) {
// if there's a device, display its name, otherwise
// display nothing
if (full.device) {
// TODO render a link to a device details page,
// passing the device.id
return full.deviceName;
}
return '';
return full.deviceName;
}
},
{data: 'issuer'},

View File

@ -68,17 +68,17 @@
// create status icon
var result = full.overallValidationResult;
var ovallMessage = full.message;
var overallMessage = full.message;
if (result) {
switch (result) {
case "PASS":
html += '<img src="${passIcon}" title="${passText}"/>';
break;
case "FAIL":
html += '<img src="${failIcon}" title="' + ovallMessage + '"/>';
html += '<img src="${failIcon}" title="' + overallMessage + '"/>';
break;
case "ERROR":
html += '<img src="${errorIcon}" title="' + ovallMessage + '"/>';
html += '<img src="${errorIcon}" title="' + overallMessage + '"/>';
break;
default:
html += unknownStatus;
@ -183,7 +183,7 @@
// the validation_type.
for (var i = 0; i < full.validations.length; i++) {
var curValidation = full.validations[i];
var curResult = curValidation.result;
var curResult = curValidation.validationResult;
var curMessage = curValidation.message;
if (curValidation.validationType === validation_type) {

View File

@ -36,8 +36,8 @@ public final class BouncyCastleUtils {
X500Name x500Name2;
try {
x500Name1 = new X500Name(nameValue1.replace(SEPARATOR_PLUS, SEPARATOR_COMMA));
x500Name2 = new X500Name(nameValue2.replace(SEPARATOR_PLUS, SEPARATOR_COMMA));
x500Name1 = new X500Name(nameValue1);
x500Name2 = new X500Name(nameValue2);
result = x500Name1.equals(x500Name2);
} catch (IllegalArgumentException iaEx) {
log.error(iaEx.toString());

View File

@ -23,8 +23,8 @@ public class UefiGuid {
*/
private static final int UUID_EPOCH_DIVISOR = 10000;
private static final Path JSON_PATH = FileSystems.getDefault().getPath("/opt",
"hirs/aca", "default-properties", "vendor-table.json");
private static final Path JSON_PATH = FileSystems.getDefault().getPath("/etc",
"hirs", "aca", "default-properties", "vendor-table.json");
private JsonObject uefiVendorRef;
/**
* guid byte array.
@ -175,10 +175,7 @@ public class UefiGuid {
* @return true if the uuid is the Empty UUID, false if not
*/
public boolean isUnknownUUID() {
if (getVendorTableReference().equals("Unknown GUID reference")) {
return true;
}
return false;
return getVendorTableReference().equals("Unknown GUID reference");
}
/**

View File

@ -37,7 +37,15 @@ DB_SRV_CONF="/etc/my.cnf.d/mariadb-server.cnf"
DB_CLIENT_CONF="/etc/my.cnf.d/client.cnf"
ALL_CHECKS_PASSED=true
ALL_CERTS_PASSED=true
source $SCRIPT_DIR/../db/mysql_util.sh
source /etc/os-release
# Setup distro specifc paths and variables
if [ $ID = "ubuntu" ]; then
DB_SRV_CONF="/etc/mysql/mariadb.conf.d/50-server.cnf"
DB_CLIENT_CONF="/etc/mysql/mariadb.conf.d/50-client.cnf"
fi
# Check for Admin privileges
if [ "$EUID" -ne 0 ]; then
@ -69,16 +77,24 @@ done
echo "Checking HIRS ACA Setup on this device..."
# Check if aca setup was performed
# Check is RPM was installed via RPM package
rpm -q --quiet HIRS_AttestationCA
if [ $ID = "rhel" ]; then
echo "RHEL distro detected"
rpm -q --quiet HIRS_AttestationCA
elif [ $ID = 'ubuntu' ]; then
echo "Ubuntu distro detected"
dpkg -l "hirs-attestationca" > /dev/null
else
echo "Unsupported OS Distro encountered"
fi
if [ $? -eq 0 ]; then
echo "HIRS ACA was installed via rpm package on this device"
echo "HIRS ACA was installed via an OS package on this device"
if [[ $(cat /etc/crontab | grep -c hirs/aca) > 0 ]]; then
echo " HIRS ACA is set to start on boot via crontab file"
else
echo " HIRS ACA is NOT set to start on boot via crontab file"
fi
else
echo "HIRS ACA was NOT installed via rpm package on this device"
echo "HIRS ACA was NOT installed via an OS package on this device"
fi
# Check install setup pki files
@ -92,7 +108,6 @@ echo "Checking HIRS ACA Setup on this device..."
source /etc/hirs/aca/aca.properties;
check_pwds () {
PRESENT=true
@ -121,13 +136,13 @@ check_mysql_setup () {
# make sure mysql is running and restart if its not...
check_mysql
# Check DB server/client TLS setup.
if [[ $(cat "$DB_SRV_CONF" | grep -c "ssl") < 1 ]]; then
if [[ $(cat "$DB_SRV_CONF" | grep -c "HIRS") < 1 ]]; then
echo " Mysql server ($DB_SRV_CONF) is NOT configured for Server Side TLS"
ALL_CHECKS_PASSED=false
else
echo " Mysql server ($DB_SRV_CONF) is configured for Server Side TLS"
fi
if [[ $(cat "$DB_CLIENT_CONF" | grep -c "ssl") < 1 ]]; then
if [[ $(cat "$DB_CLIENT_CONF" | grep -c "HIRS") < 1 ]]; then
echo " Mysql client ($DB_CLIENT_CONF)is NOT configured for command line use of TLS without provding key/cert ino the commandline"
ALL_CHECKS_PASSED=false
else
@ -240,12 +255,18 @@ check_db () {
mysql -u hirs_db --password=$hirs_db_password -e "SHOW DATABASES;";
echo "Privileges for the hirs_db user:"
mysql -u hirs_db --password=$hirs_db_password -e "SHOW GRANTS FOR 'hirs_db'@'localhost'"
echo "MYSQL Log:"
mysql -u root --password=$mysql_admin_password -e "SHOW GLOBAL VARIABLES LIKE 'log_error'"
fi
}
# Check selinux status and files that require specific contexts
check_selinux () {
if [ $ID = "ubuntu" ]; then
echo "Skipping selinux check on ubuntu"
return
fi
SELINUXSTATUS=$(getenforce)
DB_SRV_CONTEXT=$(ls -Z $DB_SRV_CONF)
DB_CLIENT_CONTEXT=$(ls -Z $DB_CLIENT_CONF)
@ -283,4 +304,4 @@ if [ $ALL_CHECKS_PASSED = true ]; then
echo "ACA setup checks passed!"
else
echo "ACA setup checks failed."
fi
fi

View File

@ -22,7 +22,7 @@ check_mysql_root
# remove the hrs-db and hirs_db user
pushd $SCRIPT_DIR/../db/ &>/dev/null
sh db_drop.sh $DB_ADMIN_PWD
./db_drop.sh $DB_ADMIN_PWD
popd &>/dev/null
# remove pki files and config files if not installed by rpm
@ -36,4 +36,4 @@ echo "Removing the ACA crontab"
sed -i '/aca_bootRun.sh/d' /etc/crontab
echo "Shutting down the aca..."
ps axf | grep HIRS_AttestationCAPortal.war | grep -v grep | awk '{print "kill " $1}' | sh >/dev/null 2>&1
echo "ACA setup removal complete."
echo "ACA setup removal complete."

View File

@ -25,7 +25,7 @@ help () {
echo " -u | --unattended Run unattended"
echo " -h | --help Print this Help."
echo " -sp | --skip-pki run the setup without pki setup."
echo " -sb | --skip-db run the setup without database setup."
echo " -sd | --skip-db run the setup without database setup."
echo
}
@ -97,7 +97,7 @@ if [ -z $HIRS_PKI_PWD ]; then
fi
if [ -z "${ARG_SKIP_PKI}" ]; then
sh ../pki/pki_setup.sh $LOG_FILE $PKI_PASS $ARG_UNATTEND
../pki/pki_setup.sh $LOG_FILE $PKI_PASS $ARG_UNATTEND
if [ $? -eq 0 ]; then
echo "ACA PKI setup complete" | tee -a "$LOG_FILE"
else
@ -109,7 +109,7 @@ if [ -z "${ARG_SKIP_PKI}" ]; then
fi
if [ -z "${ARG_SKIP_DB}" ]; then
sh ../db/db_create.sh $LOG_FILE $PKI_PASS $ARG_UNATTEND
../db/db_create.sh $LOG_FILE $PKI_PASS $ARG_UNATTEND
if [ $? -eq 0 ]; then
echo "ACA database setup complete" | tee -a "$LOG_FILE"
else
@ -122,4 +122,4 @@ fi
echo "ACA setup complete" | tee -a "$LOG_FILE"
popd &>/dev/null
popd &>/dev/null

View File

@ -8,6 +8,7 @@
################################################################################
LOG_FILE=$1
DB_LOG_FILE="/var/log/mariadb/mariadb.log"
PKI_PASS=$2
UNATTENDED=$3
RSA_PATH=rsa_3k_sha384_certs
@ -17,7 +18,7 @@ SCRIPT_DIR=$( dirname -- "$( readlink -f -- "$0"; )"; )
SPRING_PROP_FILE="/etc/hirs/aca/application.properties"
ACA_PROP_FILE="/etc/hirs/aca/aca.properties"
DB_ADMIN_PWD=""
# Db Configuration files
# Db Configuration fileis, use RHELpaths as default
DB_SRV_CONF="/etc/my.cnf.d/mariadb-server.cnf"
DB_CLIENT_CONF="/etc/my.cnf.d/client.cnf"
# Default Server Side Certificates
@ -29,16 +30,29 @@ SSL_DB_CLIENT_CHAIN="/etc/hirs/certificates/HIRS/rsa_3k_sha384_certs/HIRS_rsa_3k
SSL_DB_CLIENT_CERT="/etc/hirs/certificates/HIRS/rsa_3k_sha384_certs/HIRS_db_client_rsa_3k_sha384.pem";
SSL_DB_CLIENT_KEY="/etc/hirs/certificates/HIRS/rsa_3k_sha384_certs/HIRS_db_client_rsa_3k_sha384.key";
touch $ACA_PROP_FILE
touch $LOG_FILE
touch $DB_SRV_CONF
# Make sure required paths exist
mkdir -p /etc/hirs/aca/
mkdir -p /var/log/hirs/
source $SCRIPT_DIR/mysql_util.sh
source $ACA_PROP_FILE
source /etc/os-release
# Setup distro specifc paths and variables
if [ $ID = "ubuntu" ]; then
DB_SRV_CONF="/etc/mysql/mariadb.conf.d/50-server.cnf"
DB_CLIENT_CONF="/etc/mysql/mariadb.conf.d/50-client.cnf"
mkdir -p /var/log/mariadb >> /dev/null
if [[ $(cat "$DB_SRV_CONF" | grep -c "log-error") < 1 ]]; then
echo "log_error=/var/log/mariadb/mariadb.log" >> $DB_SRV_CONF
echo "tls_version = TLSv1.2,TLSv1.3" >> $DB_SRV_CONF
fi
fi
touch $ACA_PROP_FILE
touch $LOG_FILE
touch $DB_SRV_CONF
touch $DB_LOG_FILE
check_mysql_root_pwd () {
@ -90,8 +104,8 @@ check_mysql_root_pwd () {
}
set_mysql_server_tls () {
# Check DB server setup. If ssl params dont exist then we need to add them.
if [[ $(cat "$DB_SRV_CONF" | grep -c "ssl") < 1 ]]; then
# Check DB server setup. If HIRS ssl params dont exist then we need to add them.
if [[ $(cat "$DB_SRV_CONF" | grep -c "HIRS") < 1 ]]; then
# Add TLS files to my.cnf
echo "Updating $DB_SRV_CONF with ssl parameters..." | tee -a "$LOG_FILE"
echo "ssl_ca=$SSL_DB_SRV_CHAIN" >> "$DB_SRV_CONF"
@ -100,10 +114,12 @@ set_mysql_server_tls () {
# Make sure mysql can access them
chown mysql:mysql $SSL_DB_SRV_CHAIN $SSL_DB_SRV_CERT $SSL_DB_SRV_KEY
# Make selinux contexts for config files, if selinux is enabled
selinuxenabled
if [ $? -eq 0 ]; then
semanage fcontext -a -t mysqld_etc_t $DB_SRV_CONF > /dev/null #adds the context type to file
restorecon -v -F $DB_SRV_CONF > /dev/null # changes the file's context type
if [ $ID = "rhel" ]; then
selinuxenabled
if [ $? -eq 0 ]; then
semanage fcontext -a -t mysqld_etc_t $DB_SRV_CONF > /dev/null #adds the context type to file
restorecon -v -F $DB_SRV_CONF > /dev/null # changes the file's context type
fi
fi
else
echo "mysql.cnf contians existing entry for ssl, skipping..." | tee -a "$LOG_FILE"
@ -112,17 +128,19 @@ set_mysql_server_tls () {
set_mysql_client_tls () {
# Update ACA property file with client cert info, if not there already
if [[ $(cat "$DB_CLIENT_CONF" | grep -c "ssl") < 1 ]]; then
if [[ $(cat "$DB_CLIENT_CONF" | grep -c "HIRS") < 1 ]]; then
echo "Updating $DB_CLIENT_CONF with ssl parameters..." | tee -a "$LOG_FILE"
echo "ssl_ca=$SSL_DB_CLIENT_CHAIN" >> $DB_CLIENT_CONF
echo "ssl_cert=$SSL_DB_CLIENT_CERT" >> $DB_CLIENT_CONF
echo "ssl_key=$SSL_DB_CLIENT_KEY" >> $DB_CLIENT_CONF
chown mysql:mysql $SSL_DB_CLIENT_CHAIN $SSL_DB_CLIENT_CERT $SSL_DB_CLIENT_KEY
# Make selinux contexts for config files, if selinux is enabled
selinuxenabled
if [ $? -eq 0 ]; then
semanage fcontext -a -t mysqld_etc_t $DB_CLIENT_CONFf > /dev/null #adds the context type to file
restorecon -F $DB_CLIENT_CONF > /dev/null #changes the file's context type
if [ $ID = "rhel" ]; then
selinuxenabled
if [ $? -eq 0 ]; then
semanage fcontext -a -t mysqld_etc_t $DB_CLIENT_CONFf > /dev/null #adds the context type to file
restorecon -F $DB_CLIENT_CONF > /dev/null #changes the file's context type
fi
fi
fi
}
@ -130,7 +148,8 @@ fi
# Process HIRS DB USER
set_hirs_db_pwd () {
RESULT="$(mysql -u root --password=$DB_ADMIN_PWD -e "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = 'hirs_db')")"
RESULT="$(mysql -u root --password=$DB_ADMIN_PWD -e "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = 'hirs_db')")"
if [ "$RESULT" = 1 ]; then
echo "hirs-db user exists"
HIRS_DB_PWD=$hirs_db_password
@ -157,7 +176,8 @@ create_hirs_db_with_tls () {
else
mysql -u root --password=$DB_ADMIN_PWD < $MYSQL_DIR/db_create.sql
mysql -u root --password=$DB_ADMIN_PWD < $MYSQL_DIR/secure_mysql.sql
mysql -u root --password=$DB_ADMIN_PWD -e "ALTER USER 'hirs_db'@'localhost' IDENTIFIED BY '"$HIRS_DB_PWD"'; FLUSH PRIVILEGES;";
# mysql -u root --password=$DB_ADMIN_PWD -e "ALTER USER 'hirs_db'@'localhost' IDENTIFIED BY '"$HIRS_DB_PWD"'; FLUSH PRIVILEGES;";
mysql -u root --password=$DB_ADMIN_PWD -e "SET PASSWORD FOR 'hirs_db'@'localhost' = PASSWORD('"$HIRS_DB_PWD"'); FLUSH PRIVILEGES;";
fi
}
@ -196,6 +216,7 @@ check_for_container -p
set_mysql_server_tls
set_mysql_client_tls
start_mysqlsd
check_mysql
check_mysql_root_pwd
set_hirs_db_pwd
create_hirs_db_with_tls

View File

@ -1,13 +1,14 @@
#!/bin/bash
SRV_CNF=/etc/my.cnf.d/mariadb-server.cnf
CLIENT_CNF=/etc/my.cnf.d/client.cnf
DB_SRV_CONF=/etc/my.cnf.d/mariadb-server.cnf
DB_CLIENT_CONF=/etc/my.cnf.d/client.cnf
SCRIPT_DIR=$( dirname -- "$( readlink -f -- "$0"; )";)
LOG_FILE=/dev/null
DB_ADMIN_PWD=$1
#source /etc/hirs/aca/aca.properties;
source $SCRIPT_DIR/mysql_util.sh
source /etc/os-release
# Check for sudo or root user, not actually needed but a good idea
if [ "$EUID" -ne 0 ]
@ -15,6 +16,12 @@ if [ "$EUID" -ne 0 ]
exit 1
fi
# Setup distro specifc paths and variables
if [ $ID = "ubuntu" ]; then
DB_SRV_CONF="/etc/mysql/mariadb.conf.d/50-server.cnf"
DB_CLIENT_CONF="/etc/mysql/mariadb.conf.d/50-client.cnf"
fi
if [ -d /opt/hirs/scripts/db ]; then
MYSQL_DIR="/opt/hirs/scripts/db"
else
@ -44,8 +51,8 @@ fi
# Remove key , cert and truststore entries from client.cnf andf mariadb.cnf
echo "Removing hirs cert references from mariadb configuration files"
grep -v "hirs" $SRV_CNF > tmpfile && mv tmpfile $SRV_CNF
grep -v "hirs" $CLIENT_CNF > tmpfile && mv tmpfile $CLIENT_CNF
grep -v "hirs" $DB_SRV_CONF > tmpfile && mv tmpfile $DB_SRV_CONF
grep -v "hirs" $DB_CLIENT_CONF > tmpfile && mv tmpfile $DB_CLIENT_CONF
echo "restarting mariadb"

View File

@ -12,7 +12,7 @@ SQL_SERVICE="mariadb"
check_for_container () {
PRINT_STATUS=$1
# Check if we're in a Docker container
if [[ $(cat /proc/1/sched | head -n 1) == *"bash"* ]]; then
if [[ $(cat /proc/1/cgroup | head -n 1) == *"docker"* ]]; then
#if [ -f /.dockerenv ]; then
DOCKER_CONTAINER=true
if [[ $PRINT_STATUS == "-p" ]]; then echo "ACA is running in a container..." | tee -a "$LOG_FILE"; fi
@ -40,8 +40,13 @@ check_mariadb_install () {
# Starts mariadb during intial install
start_mysqlsd () {
PRINT_STATUS=$1
PROCESS="mysqld"
source /etc/os-release
if [ $ID = "ubuntu" ]; then
PROCESS="mariadb"
fi
# Check if mysql is already running, if not initialize
if [[ $(pgrep -c -u mysql mysqld) -eq 0 ]]; then
if [[ $(pgrep -c -u mysql $PROCESS) -eq 0 ]]; then
# Check if running in a container
if [ $DOCKER_CONTAINER = true ]; then
# if in Docker container, avoid services that invoke the D-Bus
@ -52,13 +57,12 @@ start_mysqlsd () {
chown -R mysql:mysql /var/lib/mysql/ >> "$LOG_FILE"
fi
if [[ $PRINT_STATUS == "-p" ]]; then echo "Starting mysql..."; fi
touch /var/log/mariadb/mariadb.log
chown mysql:mysql /var/log/mariadb/mariadb.log >> "$LOG_FILE";
/usr/bin/mysqld_safe & >> "$LOG_FILE";
echo "Attempting to start mariadb"
/usr/bin/mysqld_safe --skip-syslog >> "$LOG_FILE" &
chown -R mysql:mysql /var/lib/mysql/ >> "$LOG_FILE"
echo "Attempting to start mariadb"
else #not a container
systemctl enable $SQL_SERVICE & >> "$LOG_FILE";
systemctl start $SQL_SERVICE & >> "$LOG_FILE";
systemctl start $SQL_SERVICE & >> "$LOG_FILE";
fi
else # mysql process is running
# check if mysql service is running
@ -70,22 +74,22 @@ start_mysqlsd () {
fi
fi # non contanier mysql start
fi
# Wait for mysql to start before continuing.
if [[ $PRINT_STATUS == "-p" ]]; then echo "Checking mysqld status..."| tee -a "$LOG_FILE"; fi
while ! mysqladmin ping -h "$localhost" --silent; do
sleep 1;
done
if [[ $PRINT_STATUS == "-p" ]]; then echo "mysqld is running."| tee -a "$LOG_FILE"; fi
}
# Basic check for marai db status, attempts restart if not running
check_mysql () {
PROCESS="mysqld"
source /etc/os-release
if [ $ID = "ubuntu" ]; then
PROCESS="mariadb"
fi
echo "Checking mysqld status..."
if [ $DOCKER_CONTAINER = true ]; then
if [[ $(pgrep -c -u mysql mysqld) -eq 0 ]]; then
if [[ $(pgrep -c -u mysql $PROCESS ) -eq 0 ]]; then
echo "mariadb not running , attempting to restart"
/usr/bin/mysqld_safe & >> "$LOG_FILE"
chown mysql:mysql /var/log/mariadb/mariadb.log >> "$LOG_FILE";
/usr/bin/mysqld_safe --skip-syslog >> "$LOG_FILE" &
fi
else # not in a contianer
DB_STATUS=$(systemctl status mysql |grep 'running' | wc -l )
@ -95,12 +99,24 @@ check_mysql () {
fi
fi
# Wait for mysql to start before continuing.
while ! mysqladmin ping -h "$localhost" --silent; do
sleep 1;
# Wait for mysql to start before continuing.
count=1;
if [[ $PRINT_STATUS == "-p" ]]; then echo "Testing mysqld connection..."| tee -a "$LOG_FILE"; fi
until mysqladmin ping -h "localhost" --silent ; do
((count++))
if [[ $count -gt 20 ]]; then
break;
fi
sleep 1;
done
echo " Mariadb is running."
if [[ $count -gt 20 ]]; then
echo "Timed out waiting for Mariadb to respond"
exit 1;
else
echo "Mariadb started"
fi
}
# Check for mysql root password , abort if not available
@ -163,5 +179,5 @@ mysqld_reboot () {
mysql -u root --password=$DB_ADMIN_PWD -e "SHUTDOWN"
sleep 2
check_for_container
start_mysqlsd
}
start_mysqlsd >> "$LOG_FILE";
}

View File

@ -225,6 +225,9 @@ create_cert_chain () {
-srcstorepass $PASS -destkeystore $DB_CLIENT.jks -deststoretype JKS -deststorepass $PASS >> "$LOG_FILE" 2>&1
}
# Needed for older versions of openssl
#openssl rand -writerand .rnd
if [ "$ASYM_ALG" == "rsa" ]; then
# Create Root CA key pair and self signed cert
echo "Generating RSA Root CA ...." | tee -a "$LOG_FILE"
@ -255,4 +258,4 @@ if [ "$ASYM_ALG" == "ecc" ]; then
add_to_stores $PKI_ROOT
# Create an intermediate CA, 2 Leaf CAs, and Signer Certs
create_cert_chain
fi
fi

View File

@ -42,8 +42,8 @@ if [ -z "$PKI_PASS" ]; then
fi
# Check for sudo or root user
if [ "$EUID" -ne 0 ]
then echo "This script requires root. Please run as root" | tee -a "$LOG_FILE"
if [ "$EUID" -ne 0 ]; then
echo "This script requires root. Please run as root" | tee -a "$LOG_FILE"
exit 1
fi
@ -61,8 +61,8 @@ if [ ! -d "/etc/hirs/certificates" ]; then
pushd /etc/hirs/certificates/ &> /dev/null
cp $PKI_SETUP_DIR/ca.conf .
sh $PKI_SETUP_DIR/pki_chain_gen.sh "HIRS" "rsa" "3072" "sha384" "$PKI_PASS" "$LOG_FILE"
sh $PKI_SETUP_DIR/pki_chain_gen.sh "HIRS" "ecc" "512" "sha384" "$PKI_PASS" "$LOG_FILE"
$PKI_SETUP_DIR/pki_chain_gen.sh "HIRS" "rsa" "3072" "sha384" "$PKI_PASS" "$LOG_FILE"
$PKI_SETUP_DIR/pki_chain_gen.sh "HIRS" "ecc" "512" "sha384" "$PKI_PASS" "$LOG_FILE"
popd &> /dev/null
echo "hirs_pki_password="$PKI_PASS >> $ACA_PROP

View File

@ -1,5 +0,0 @@
echo "
# *** ACA Directories ***
aca.directories.root = /etc/hirs/
aca.prop.file=aca.directories.root/aca.properties
aca.directories.certificates = root/certificates"