fixed merge conflict

This commit is contained in:
iadgovuser26 2024-03-14 15:57:56 -04:00
commit 8e1ec11c41
88 changed files with 5027 additions and 896 deletions

View File

@ -3,6 +3,9 @@ LABEL org.opencontainers.image.vendor NSA Laboratory for Advanced Cybersecurity
LABEL org.opencontainers.image.source https://github.com/nsacyber/hirs LABEL org.opencontainers.image.source https://github.com/nsacyber/hirs
LABEL org.opencontainers.image.description NSA\'s HIRS Attestation Certificate Authority. Expose port 8443 to access the portal from outside the container. LABEL org.opencontainers.image.description NSA\'s HIRS Attestation Certificate Authority. Expose port 8443 to access the portal from outside the container.
# REF can be specified as a docker run environment variable to select the HIRS branch to work with
ARG REF=main
SHELL ["/bin/bash", "-c"] SHELL ["/bin/bash", "-c"]
# Rocky 9 has a different channel for some apps # Rocky 9 has a different channel for some apps
@ -50,7 +53,7 @@ RUN echo "#!/bin/bash" > /tmp/tpm_config && \
EXPOSE 8443 EXPOSE 8443
# Checkout HIRS # Checkout HIRS
RUN git clone -b main https://github.com/nsacyber/HIRS.git /repo RUN git clone -b ${REF} https://github.com/nsacyber/HIRS.git /repo
# Defensive copy of the repo so it's easy to start fresh if needed # Defensive copy of the repo so it's easy to start fresh if needed
RUN mkdir /hirs RUN mkdir /hirs

View File

@ -9,6 +9,9 @@ LABEL org.opencontainers.image.source https://github.com/nsacyber/hirs
LABEL org.opencontainers.image.description NSA\'s HIRS Attestation Certificate Authority in a Windows-native image. Expose port 8443 to access the portal from outside the container. LABEL org.opencontainers.image.description NSA\'s HIRS Attestation Certificate Authority in a Windows-native image. Expose port 8443 to access the portal from outside the container.
LABEL org.opencontainers.image.base.name mcr.microsoft.com/powershell:${BASE_IMAGE_TAG} LABEL org.opencontainers.image.base.name mcr.microsoft.com/powershell:${BASE_IMAGE_TAG}
# REF can be specified as a docker run environment variable to select the HIRS branch to work with
ARG REF=main
SHELL ["pwsh", "-Command"] SHELL ["pwsh", "-Command"]
# Output Powershell Version # Output Powershell Version
@ -105,11 +108,11 @@ RUN setx PATH '%JAVA_HOME%\bin;C:\Program Files\MariaDB 11.1\bin;%GIT_HOME%\bin;
# Echo PATH after update # Echo PATH after update
RUN echo $Env:PATH RUN echo $Env:PATH
# Clone HIRS main # Clone HIRS main (or REF)
WORKDIR C:/ WORKDIR C:/
RUN git config --global --add core.autocrlf false RUN git config --global --add core.autocrlf false
RUN git config --global --add safe.directory '*' RUN git config --global --add safe.directory '*'
RUN git clone -b main https://github.com/nsacyber/hirs.git C:/repo RUN git clone -b ${REF} https://github.com/nsacyber/hirs.git C:/repo
# Defensive copy of the repo so it's easy to start fresh if needed # Defensive copy of the repo so it's easy to start fresh if needed
WORKDIR C:/repo WORKDIR C:/repo

View File

@ -51,6 +51,7 @@ jobs:
echo "PUBLIC_IMAGE_TAG=$PUBLIC_IMAGE_NAME:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" echo "PUBLIC_IMAGE_TAG=$PUBLIC_IMAGE_NAME:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT"
- name: Print env - name: Print env
run: | run: |
echo GITHUB_REF_NAME=${{ github.ref_name }}
echo DOCKERFILE_ROCKY=$DOCKERFILE_ROCKY echo DOCKERFILE_ROCKY=$DOCKERFILE_ROCKY
echo DOCKERFILE_WINDOWS=$DOCKERFILE_WINDOWS echo DOCKERFILE_WINDOWS=$DOCKERFILE_WINDOWS
echo IMAGE_NAME_ROCKY=$IMAGE_NAME_ROCKY echo IMAGE_NAME_ROCKY=$IMAGE_NAME_ROCKY
@ -86,6 +87,7 @@ jobs:
with: with:
context: "{{defaultContext}}:.ci/docker" context: "{{defaultContext}}:.ci/docker"
file: Dockerfile.${{env.DOCKERFILE_ROCKY}} file: Dockerfile.${{env.DOCKERFILE_ROCKY}}
build-args: REF=${{ github.ref_name }}
tags: ${{env.TAG}} tags: ${{env.TAG}}
push: true push: true
@ -108,7 +110,7 @@ jobs:
- name: Build the docker image for ${{ github.repository }} - name: Build the docker image for ${{ github.repository }}
run: | run: |
cd ./.ci/docker cd ./.ci/docker
docker build -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} . docker build --build-arg "REF=${{ github.ref_name }}" -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} .
- name: Push the docker image - name: Push the docker image
run: | run: |
@ -133,7 +135,7 @@ jobs:
- name: Build the docker image for ${{ github.repository }} - name: Build the docker image for ${{ github.repository }}
run: | run: |
cd ./.ci/docker cd ./.ci/docker
docker build -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} --build-arg BASE_IMAGE_TAG=lts-windowsservercore-1809 . docker build --build-arg "REF=${{ github.ref_name }}" -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} --build-arg BASE_IMAGE_TAG=lts-windowsservercore-1809 .
- name: Push the docker image - name: Push the docker image
run: | run: |

View File

@ -52,6 +52,7 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3' testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
testImplementation 'org.junit.platform:junit-platform-launcher:1.9.3' testImplementation 'org.junit.platform:junit-platform-launcher:1.9.3'
testImplementation 'org.mockito:mockito-core:4.2.0' testImplementation 'org.mockito:mockito-core:4.2.0'
testImplementation 'org.springframework:spring-test:6.0.8'
// spring management // spring management
compileOnly libs.lombok compileOnly libs.lombok

View File

@ -15,5 +15,9 @@
<Match> <Match>
<Bug pattern="EI_EXPOSE_REP2" /> <Bug pattern="EI_EXPOSE_REP2" />
</Match> </Match>
<Match>
<Class name="hirs.attestationca.persist.AttestationCertificateAuthorityTest"/>
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
</Match>
</FindBugsFilter> </FindBugsFilter>

View File

@ -1,6 +1,7 @@
package hirs.attestationca.persist; package hirs.attestationca.persist;
import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentInfoRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository; import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository; import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.manager.IssuedCertificateRepository; import hirs.attestationca.persist.entity.manager.IssuedCertificateRepository;
@ -52,6 +53,7 @@ public abstract class AttestationCertificateAuthority {
private Integer validDays = 1; private Integer validDays = 1;
private final ComponentResultRepository componentResultRepository; private final ComponentResultRepository componentResultRepository;
private ComponentInfoRepository componentInfoRepository;
private final CertificateRepository certificateRepository; private final CertificateRepository certificateRepository;
private final IssuedCertificateRepository issuedCertificateRepository; private final IssuedCertificateRepository issuedCertificateRepository;
private final ReferenceManifestRepository referenceManifestRepository; private final ReferenceManifestRepository referenceManifestRepository;
@ -71,13 +73,14 @@ public abstract class AttestationCertificateAuthority {
* @param acaCertificate the ACA certificate * @param acaCertificate the ACA certificate
* @param structConverter the struct converter * @param structConverter the struct converter
* @param componentResultRepository the component result manager * @param componentResultRepository the component result manager
* @param componentInfoRepository the component info manager
* @param certificateRepository the certificate manager * @param certificateRepository the certificate manager
* @param referenceManifestRepository the Reference Manifest manager * @param referenceManifestRepository the Reference Manifest manager
* @param validDays the number of days issued certs are valid * @param validDays the number of days issued certs are valid
* @param deviceRepository the device manager * @param deviceRepository the device manager
* @param referenceDigestValueRepository the reference event manager * @param referenceDigestValueRepository the reference event manager
* @param policyRepository * @param policyRepository policy setting repository
* @param tpm2ProvisionerStateRepository * @param tpm2ProvisionerStateRepository tpm2 provisioner state repository
*/ */
@SuppressWarnings("checkstyle:parameternumber") @SuppressWarnings("checkstyle:parameternumber")
public AttestationCertificateAuthority( public AttestationCertificateAuthority(
@ -85,6 +88,7 @@ public abstract class AttestationCertificateAuthority {
final PrivateKey privateKey, final X509Certificate acaCertificate, final PrivateKey privateKey, final X509Certificate acaCertificate,
final StructConverter structConverter, final StructConverter structConverter,
final ComponentResultRepository componentResultRepository, final ComponentResultRepository componentResultRepository,
final ComponentInfoRepository componentInfoRepository,
final CertificateRepository certificateRepository, final CertificateRepository certificateRepository,
final IssuedCertificateRepository issuedCertificateRepository, final IssuedCertificateRepository issuedCertificateRepository,
final ReferenceManifestRepository referenceManifestRepository, final ReferenceManifestRepository referenceManifestRepository,
@ -98,6 +102,7 @@ public abstract class AttestationCertificateAuthority {
this.acaCertificate = acaCertificate; this.acaCertificate = acaCertificate;
this.structConverter = structConverter; this.structConverter = structConverter;
this.componentResultRepository = componentResultRepository; this.componentResultRepository = componentResultRepository;
this.componentInfoRepository = componentInfoRepository;
this.certificateRepository = certificateRepository; this.certificateRepository = certificateRepository;
this.issuedCertificateRepository = issuedCertificateRepository; this.issuedCertificateRepository = issuedCertificateRepository;
this.referenceManifestRepository = referenceManifestRepository; this.referenceManifestRepository = referenceManifestRepository;
@ -111,8 +116,8 @@ public abstract class AttestationCertificateAuthority {
certificateRepository, deviceRepository, certificateRepository, deviceRepository,
privateKey, acaCertificate, validDays, tpm2ProvisionerStateRepository); privateKey, acaCertificate, validDays, tpm2ProvisionerStateRepository);
this.identityClaimHandler = new IdentityClaimProcessor(supplyChainValidationService, this.identityClaimHandler = new IdentityClaimProcessor(supplyChainValidationService,
certificateRepository, referenceManifestRepository, certificateRepository, componentResultRepository, componentInfoRepository,
referenceDigestValueRepository, referenceManifestRepository, referenceDigestValueRepository,
deviceRepository, tpm2ProvisionerStateRepository, policyRepository); deviceRepository, tpm2ProvisionerStateRepository, policyRepository);
} }

View File

@ -1,6 +1,7 @@
package hirs.attestationca.persist; package hirs.attestationca.persist;
import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentInfoRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository; import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository; import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.manager.IssuedCertificateRepository; import hirs.attestationca.persist.entity.manager.IssuedCertificateRepository;
@ -10,7 +11,6 @@ import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.manager.TPM2ProvisionerStateRepository; import hirs.attestationca.persist.entity.manager.TPM2ProvisionerStateRepository;
import hirs.attestationca.persist.service.SupplyChainValidationService; import hirs.attestationca.persist.service.SupplyChainValidationService;
import hirs.structs.converters.StructConverter; import hirs.structs.converters.StructConverter;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
@ -63,6 +63,7 @@ public class RestfulAttestationCertificateAuthority extends AttestationCertifica
final PrivateKey privateKey, final X509Certificate acaCertificate, final PrivateKey privateKey, final X509Certificate acaCertificate,
final StructConverter structConverter, final StructConverter structConverter,
final ComponentResultRepository componentResultRepository, final ComponentResultRepository componentResultRepository,
final ComponentInfoRepository componentInfoRepository,
final CertificateRepository certificateRepository, final CertificateRepository certificateRepository,
final IssuedCertificateRepository issuedCertificateRepository, final IssuedCertificateRepository issuedCertificateRepository,
final ReferenceManifestRepository referenceManifestRepository, final ReferenceManifestRepository referenceManifestRepository,
@ -72,7 +73,8 @@ public class RestfulAttestationCertificateAuthority extends AttestationCertifica
final PolicyRepository policyRepository, final PolicyRepository policyRepository,
final TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository) { final TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository) {
super(supplyChainValidationService, privateKey, acaCertificate, structConverter, super(supplyChainValidationService, privateKey, acaCertificate, structConverter,
componentResultRepository, certificateRepository, issuedCertificateRepository, componentResultRepository, componentInfoRepository,
certificateRepository, issuedCertificateRepository,
referenceManifestRepository, referenceManifestRepository,
validDays, deviceRepository, validDays, deviceRepository,
referenceDigestValueRepository, policyRepository, tpm2ProvisionerStateRepository); referenceDigestValueRepository, policyRepository, tpm2ProvisionerStateRepository);

View File

@ -0,0 +1,32 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentAttributeResult;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.UUID;
public interface ComponentAttributeRepository extends JpaRepository<ComponentAttributeResult, UUID> {
/**
* Query to look up Attribute Results based on the PlatformCredential's
* db component id.
* @param componentId the unique id for the component identifier
* @return a list of attribute results
*/
List<ComponentAttributeResult> findByComponentId(UUID componentId);
/**
* Query to look up Attribute Results based on the validation id.
* @param provisionSessionId unique id generated to link supply chain summary
* @return a list of attribute results
*/
List<ComponentAttributeResult> findByProvisionSessionId(UUID provisionSessionId);
/**
* Query to look up Attribute Results based on the component id and the session id.
* @param componentId the unique id for the component identifier
* @param provisionSessionId unique id generated to link supply chain summary
* @return a list of attribute results
*/
List<ComponentAttributeResult> findByComponentIdAndProvisionSessionId(UUID componentId, UUID provisionSessionId);
}

View File

@ -0,0 +1,25 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.UUID;
public interface ComponentInfoRepository extends JpaRepository<ComponentInfo, UUID> {
/**
* Query that retrieves device components by device name.
* @param deviceName string for the host name
* @return a list of device components
*/
List<ComponentInfo> findByDeviceName(String deviceName);
/**
* Query that retrieves device components by device name and
* the component serial number.
* @param deviceName string for the host name
* @param componentSerial string for the component serial
* @return a list of device components
*/
List<ComponentInfo> findByDeviceNameAndComponentSerial(String deviceName, String componentSerial);
}

View File

@ -2,7 +2,6 @@ package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult; import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
@ -11,6 +10,19 @@ import java.util.UUID;
@Repository @Repository
public interface ComponentResultRepository extends JpaRepository<ComponentResult, UUID> { public interface ComponentResultRepository extends JpaRepository<ComponentResult, UUID> {
@Query(value = "SELECT * FROM ComponentResult where certificateId = ?1", nativeQuery = true) /**
List<ComponentResult> getComponentResultsByCertificate(UUID certificateId); * Query based on the device serial number.
* @param boardSerialNumber variable holding the device serial number
* @return a list of component result.
*/
List<ComponentResult> findByBoardSerialNumber(String boardSerialNumber);
/**
* Query based on certificate serial number and device serial number.
* @param certificateSerialNumber certificate specific serial number
* @param boardSerialNumber variable holding the device serial number
* @return a list of component result.
*/
List<ComponentResult> findByCertificateSerialNumberAndBoardSerialNumber(
String certificateSerialNumber, String boardSerialNumber);
} }

View File

@ -2,7 +2,6 @@ package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue; import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;

View File

@ -90,7 +90,8 @@ public class TPM2ProvisionerState {
/** /**
* Convenience method for finding the {@link TPM2ProvisionerState} associated with the nonce. * 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} * {@link TPM2ProvisionerState}
* @param nonce the nonce to use as the key 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; * @return the {@link TPM2ProvisionerState} associated with the nonce;

View File

@ -115,8 +115,7 @@ public class Device extends AbstractEntity {
public String toString() { public String toString() {
return String.format("Device Name: %s%nStatus: %s%nSummary: %s%n", return String.format("Device Name: %s%nStatus: %s%nSummary: %s%n",
name, healthStatus.getStatus(), name, healthStatus.getStatus(),
supplyChainValidationStatus.toString(), supplyChainValidationStatus.toString());
summaryId);
} }
@Override @Override

View File

@ -46,6 +46,7 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
private static final String DEVICE_ID_FIELD = "device.id"; private static final String DEVICE_ID_FIELD = "device.id";
@Getter
@Column @Column
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
private final AppraisalStatus.Status overallValidationResult; private final AppraisalStatus.Status overallValidationResult;
@ -58,6 +59,9 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
targetEntity = SupplyChainValidation.class, orphanRemoval = true) targetEntity = SupplyChainValidation.class, orphanRemoval = true)
private final Set<SupplyChainValidation> validations; private final Set<SupplyChainValidation> validations;
@Column
private UUID provisionSessionId;
/** /**
* Default constructor necessary for Hibernate. * Default constructor necessary for Hibernate.
*/ */
@ -177,6 +181,20 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
return new SupplyChainValidationSummary.Selector(certMan); return new SupplyChainValidationSummary.Selector(certMan);
} }
/**
* Construct a new SupplyChainValidationSummary.
*
* @param device device that underwent supply chain validation
* @param validations a Collection of Validations that should comprise this summary; not null
* @param provisionSessionId randomly generated UUID to associate with results
*/
public SupplyChainValidationSummary(final Device device,
final Collection<SupplyChainValidation> validations,
final UUID provisionSessionId) {
this(device, validations);
this.provisionSessionId = provisionSessionId;
}
/** /**
* Construct a new SupplyChainValidationSummary. * Construct a new SupplyChainValidationSummary.
* *
@ -212,13 +230,6 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
return new Device(this.device.getDeviceInfo()); return new Device(this.device.getDeviceInfo());
} }
/**
* @return the overall appraisal result
*/
public AppraisalStatus.Status getOverallValidationResult() {
return overallValidationResult;
}
/** /**
* @return the validations that this summary contains * @return the validations that this summary contains
*/ */

View File

@ -1,38 +1,142 @@
package hirs.attestationca.persist.entity.userdefined.certificate; package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.AbstractEntity; import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentAddress;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.AttributeStatus;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID;
@EqualsAndHashCode(callSuper=false) /**
* A component result is a DO to hold the status of a component validation status. This will
* also be used to display this common information on the certificate details page.
*/
@Getter @Getter
@Entity @Entity
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor(access = AccessLevel.PROTECTED) @NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ComponentResult extends AbstractEntity { public class ComponentResult extends ArchivableEntity {
private UUID certificateId; // embedded component info
private int componentHash; @Setter
private String expected; private String manufacturer;
private String actual; @Setter
private boolean mismatched; private String model;
private String serialNumber;
private String revisionNumber;
private boolean fieldReplaceable = false;
// this is a string because component class doesn't inherit serializable.
@Setter
private String componentClassValue;
private String componentClassStr;
private String componentClassType;
private AttributeStatus attributeStatus;
private String componentAddress;
private boolean version2 = false;
@Setter
private boolean failedValidation;
private String certificateType;
public ComponentResult(final UUID certificateId, final int componentHash, private String issuerDN;
final String expected, final String actual) { private String certificateSerialNumber;
this.certificateId = certificateId; private String boardSerialNumber;
this.componentHash = componentHash; private String uniformResourceIdentifier;
this.expected = expected;
this.actual = actual;
this.mismatched = Objects.equals(expected, actual); /**
* Default constructor.
* @param boardSerialNumber associated platform certificate serial number.
* @param certificateSerialNumber unique number associated with header info.
* @param certificateType parameter holds version 1.2 or 2.0.
* @param componentIdentifier object with information from the platform certificate components.
*/
public ComponentResult(final String boardSerialNumber, final String certificateSerialNumber,
final String certificateType,
final ComponentIdentifier componentIdentifier) {
this.boardSerialNumber = boardSerialNumber;
this.certificateSerialNumber = certificateSerialNumber;
this.certificateType = certificateType;
this.manufacturer = componentIdentifier.getComponentManufacturer().toString();
this.model = componentIdentifier.getComponentModel().toString();
this.serialNumber = componentIdentifier.getComponentSerial().toString();
this.revisionNumber = componentIdentifier.getComponentRevision().toString();
if (componentIdentifier.getFieldReplaceable() != null) {
this.fieldReplaceable = componentIdentifier.getFieldReplaceable().isTrue();
} }
StringBuilder sb = new StringBuilder();
for (ComponentAddress element : componentIdentifier.getComponentAddress()) {
sb.append(String.format("%s:%s;", element.getAddressTypeValue(),
element.getAddressValue().toString()));
}
componentAddress = sb.toString();
// V2 fields
if (componentIdentifier.isVersion2()
&& componentIdentifier instanceof ComponentIdentifierV2) {
// this is a downside of findbugs, the code is set up to indicate if a CI is V2 or not
// but find bugs is throwing a flag because instanceof isn't being used.
ComponentIdentifierV2 ciV2 = (ComponentIdentifierV2) componentIdentifier;
this.componentClassValue = ciV2.getComponentClass().getComponentIdentifier();
this.componentClassStr = ciV2.getComponentClass().toString();
this.componentClassType = ciV2.getComponentClass().getRegistryType();
this.attributeStatus = ciV2.getAttributeStatus();
this.version2 = true;
if (ciV2.getCertificateIdentifier() != null) {
this.issuerDN = ciV2.getCertificateIdentifier().getIssuerDN().toString();
if (ciV2.getComponentPlatformUri() != null) {
this.uniformResourceIdentifier = ciV2.getComponentPlatformUri()
.getUniformResourceIdentifier().toString();
}
}
}
}
/**
* This method is only used by the certificate-details.jsp page. This
* method splits the compiled string of addresses into the component address
* object for display on the jsp page.
* @return a collection of component addresses.
*/
public List<ComponentAddress> getComponentAddresses() {
List<ComponentAddress> addresses = new LinkedList<>();
ComponentAddress address;
if (componentAddress != null && !componentAddress.isEmpty()) {
for (String s : componentAddress.split(";", 0)) {
address = new ComponentAddress();
address.setAddressTypeString(s.split(":")[0]);
address.setAddressValueString(s.split(":")[1]);
addresses.add(address);
}
}
return addresses;
}
/**
* Returns a hash code that is associated with common fields for components.
* @return int value of the elements
*/
public int hashCommonElements() {
return Objects.hash(manufacturer,
model, serialNumber, revisionNumber, componentClassValue);
}
/**
* The string method for log entries.
* @return a string for the component result
*/
public String toString() { public String toString() {
return String.format("ComponentResult[%d]: expected=[%s] actual=[%s]", return String.format("ComponentResult: certificateSerialNumber=[%s] "
componentHash, expected, actual); + "manufacturer=[%s] model=[%s] componentClass=[%s]",
boardSerialNumber, manufacturer, model, componentClassValue);
} }
} }

View File

@ -7,7 +7,6 @@ import hirs.attestationca.persist.entity.userdefined.certificate.attributes.Plat
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TBBSecurityAssertion; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TBBSecurityAssertion;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2;
import hirs.attestationca.persist.service.selector.CertificateSelector;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Transient; import jakarta.persistence.Transient;

View File

@ -32,6 +32,8 @@ public class ComponentAddress {
private ASN1ObjectIdentifier addressType; private ASN1ObjectIdentifier addressType;
private ASN1UTF8String addressValue; private ASN1UTF8String addressValue;
private String addressTypeString;
private String addressValueString;
/** /**
* Default constructor. * Default constructor.

View File

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

View File

@ -52,6 +52,7 @@ public class ComponentClass {
private String category, categoryStr; private String category, categoryStr;
@Getter @Getter
private String component, componentStr; private String component, componentStr;
@Getter
private String registryType; private String registryType;
@Getter @Getter
private String componentIdentifier; private String componentIdentifier;

View File

@ -1,6 +1,5 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes; package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -37,10 +36,6 @@ import java.util.stream.Collectors;
@EqualsAndHashCode @EqualsAndHashCode
public class ComponentIdentifier { public class ComponentIdentifier {
/**
* Variable for components that aren't set.
*/
public static final String EMPTY_COMPONENT = "[Empty]";
/** /**
* Variable for components that aren't set. * Variable for components that aren't set.
*/ */
@ -88,8 +83,8 @@ public class ComponentIdentifier {
public ComponentIdentifier() { public ComponentIdentifier() {
componentManufacturer = new DERUTF8String(NOT_SPECIFIED_COMPONENT); componentManufacturer = new DERUTF8String(NOT_SPECIFIED_COMPONENT);
componentModel = new DERUTF8String(NOT_SPECIFIED_COMPONENT); componentModel = new DERUTF8String(NOT_SPECIFIED_COMPONENT);
componentSerial = new DERUTF8String(EMPTY_COMPONENT); componentSerial = new DERUTF8String(NOT_SPECIFIED_COMPONENT);
componentRevision = new DERUTF8String(EMPTY_COMPONENT); componentRevision = new DERUTF8String(NOT_SPECIFIED_COMPONENT);
componentManufacturerId = null; componentManufacturerId = null;
fieldReplaceable = null; fieldReplaceable = null;
componentAddress = new ArrayList<>(); componentAddress = new ArrayList<>();
@ -124,13 +119,13 @@ public class ComponentIdentifier {
/** /**
* Constructor given the SEQUENCE that contains Component Identifier. * Constructor given the SEQUENCE that contains Component Identifier.
* @param sequence containing the the component identifier * @param sequence containing the component identifier
* @throws IllegalArgumentException if there was an error on the parsing * @throws IllegalArgumentException if there was an error on the parsing
*/ */
public ComponentIdentifier(final ASN1Sequence sequence) throws IllegalArgumentException { public ComponentIdentifier(final ASN1Sequence sequence) throws IllegalArgumentException {
// set all optional values to default in case they aren't set. // set all optional values to default in case they aren't set.
this(); this();
//Check if it have a valid number of identifiers //Check if it has a valid number of identifiers
if (sequence.size() < MANDATORY_ELEMENTS) { if (sequence.size() < MANDATORY_ELEMENTS) {
throw new IllegalArgumentException("Component identifier do not have required values."); throw new IllegalArgumentException("Component identifier do not have required values.");
} }
@ -238,7 +233,7 @@ public class ComponentIdentifier {
sb.append(fieldReplaceable.toString()); sb.append(fieldReplaceable.toString());
} }
sb.append(", componentAddress="); sb.append(", componentAddress=");
if (componentAddress.size() > 0) { if (!componentAddress.isEmpty()) {
sb.append(componentAddress sb.append(componentAddress
.stream() .stream()
.map(Object::toString) .map(Object::toString)

View File

@ -25,7 +25,7 @@ public class PlatformConfigurationV1 extends PlatformConfiguration {
/** /**
* Constructor given the SEQUENCE that contains Platform Configuration. * Constructor given the SEQUENCE that contains Platform Configuration.
* @param sequence containing the the Platform Configuration. * @param sequence containing the Platform Configuration.
* @throws IllegalArgumentException if there was an error on the parsing * @throws IllegalArgumentException if there was an error on the parsing
*/ */
public PlatformConfigurationV1(final ASN1Sequence sequence) throws IllegalArgumentException { public PlatformConfigurationV1(final ASN1Sequence sequence) throws IllegalArgumentException {

View File

@ -103,13 +103,13 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
/** /**
* Constructor given the SEQUENCE that contains Component Identifier. * Constructor given the SEQUENCE that contains Component Identifier.
* @param sequence containing the the component identifier * @param sequence containing the component identifier
* @throws IllegalArgumentException if there was an error on the parsing * @throws IllegalArgumentException if there was an error on the parsing
*/ */
public ComponentIdentifierV2(final ASN1Sequence sequence) public ComponentIdentifierV2(final ASN1Sequence sequence)
throws IllegalArgumentException { throws IllegalArgumentException {
super(); super();
// Check if it have a valid number of identifiers // Check if it has a valid number of identifiers
if (sequence.size() < MANDATORY_ELEMENTS) { if (sequence.size() < MANDATORY_ELEMENTS) {
throw new IllegalArgumentException("Component identifier do not have required values."); throw new IllegalArgumentException("Component identifier do not have required values.");
} }

View File

@ -1,36 +1,39 @@
package hirs.attestationca.persist.entity.userdefined.info; package hirs.attestationca.persist.entity.userdefined.info;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.utils.enums.DeviceInfoEnums;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.DiscriminatorColumn; import jakarta.persistence.DiscriminatorColumn;
import jakarta.persistence.DiscriminatorType; import jakarta.persistence.DiscriminatorType;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlElement;
import lombok.Data; import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.Serializable; import java.util.Objects;
/** /**
* ComponentInfo is a class to hold Hardware component information * ComponentInfo is a class to hold Hardware component information
* such as manufacturer, model, serial number and version. * such as manufacturer, model, serial number and version.
*/ */
@Log4j2 @Log4j2
@NoArgsConstructor
@Data
@Entity @Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DiscriminatorColumn(name = "componentTypeEnum", discriminatorType = DiscriminatorType.STRING) @DiscriminatorColumn(name = "componentTypeEnum", discriminatorType = DiscriminatorType.STRING)
public class ComponentInfo implements Serializable { public class ComponentInfo extends ArchivableEntity {
@Id // @Id
@Column(name = "componentInfo_id") // @Column(name = "componentInfo_id")
@GeneratedValue(strategy = GenerationType.AUTO) // @GeneratedValue(strategy = GenerationType.AUTO)
private Long id; // private Long id;
@Column(nullable = false)
private String deviceName;
@XmlElement @XmlElement
@Column(nullable = false) @Column(nullable = false)
private String componentManufacturer; private String componentManufacturer;
@ -52,7 +55,7 @@ public class ComponentInfo implements Serializable {
private String componentClass; private String componentClass;
/** /**
* Constructor. * Base constructor for children.
* @param componentManufacturer Component Manufacturer (must not be null) * @param componentManufacturer Component Manufacturer (must not be null)
* @param componentModel Component Model (must not be null) * @param componentModel Component Model (must not be null)
* @param componentSerial Component Serial Number (can be null) * @param componentSerial Component Serial Number (can be null)
@ -62,6 +65,22 @@ public class ComponentInfo implements Serializable {
final String componentModel, final String componentModel,
final String componentSerial, final String componentSerial,
final String componentRevision) { final String componentRevision) {
this(DeviceInfoEnums.NOT_SPECIFIED, componentManufacturer, componentModel,
componentSerial, componentRevision);
}
/**
* Constructor.
* @param deviceName the host machine associated with this component. (must not be null)
* @param componentManufacturer Component Manufacturer (must not be null)
* @param componentModel Component Model (must not be null)
* @param componentSerial Component Serial Number (can be null)
* @param componentRevision Component Revision or Version (can be null)
*/
public ComponentInfo(final String deviceName,
final String componentManufacturer,
final String componentModel,
final String componentSerial,
final String componentRevision) {
if (isComplete( if (isComplete(
componentManufacturer, componentManufacturer,
componentModel, componentModel,
@ -72,61 +91,40 @@ public class ComponentInfo implements Serializable {
throw new NullPointerException("ComponentInfo: manufacturer and/or " throw new NullPointerException("ComponentInfo: manufacturer and/or "
+ "model can not be null"); + "model can not be null");
} }
this.deviceName = deviceName;
this.componentManufacturer = componentManufacturer.trim(); this.componentManufacturer = componentManufacturer.trim();
this.componentModel = componentModel.trim(); this.componentModel = componentModel.trim();
if (componentSerial != null) { if (componentSerial != null) {
this.componentSerial = componentSerial.trim(); this.componentSerial = componentSerial.trim();
} else { } else {
this.componentSerial = StringUtils.EMPTY; this.componentSerial = ComponentIdentifier.NOT_SPECIFIED_COMPONENT;
} }
if (componentRevision != null) { if (componentRevision != null) {
this.componentRevision = componentRevision.trim(); this.componentRevision = componentRevision.trim();
} else { } else {
this.componentRevision = StringUtils.EMPTY; this.componentRevision = ComponentIdentifier.NOT_SPECIFIED_COMPONENT;
} }
} }
/** /**
* Constructor. * Constructor.
* @param deviceName the host machine associated with this component.
* @param componentManufacturer Component Manufacturer (must not be null) * @param componentManufacturer Component Manufacturer (must not be null)
* @param componentModel Component Model (must not be null) * @param componentModel Component Model (must not be null)
* @param componentSerial Component Serial Number (can be null) * @param componentSerial Component Serial Number (can be null)
* @param componentRevision Component Revision or Version (can be null) * @param componentRevision Component Revision or Version (can be null)
* @param componentClass Component Class (can be null) * @param componentClass Component Class (can be null)
*/ */
public ComponentInfo(final String componentManufacturer, public ComponentInfo(final String deviceName,
final String componentManufacturer,
final String componentModel, final String componentModel,
final String componentSerial, final String componentSerial,
final String componentRevision, final String componentRevision,
final String componentClass) { final String componentClass) {
if (isComplete( this(deviceName, componentManufacturer, componentModel,
componentManufacturer, componentSerial, componentRevision);
componentModel,
componentSerial,
componentRevision)) {
log.error("ComponentInfo: manufacturer and/or "
+ "model can not be null");
throw new NullPointerException("ComponentInfo: manufacturer and/or "
+ "model can not be null");
}
this.componentManufacturer = componentManufacturer.trim();
this.componentModel = componentModel.trim();
if (componentSerial != null) {
this.componentSerial = componentSerial.trim();
} else {
this.componentSerial = StringUtils.EMPTY;
}
if (componentRevision != null) {
this.componentRevision = componentRevision.trim();
} else {
this.componentRevision = StringUtils.EMPTY;
}
if (componentClass != null) { this.componentClass = Objects.requireNonNullElse(componentClass, StringUtils.EMPTY);
this.componentClass = componentClass;
} else {
this.componentClass = StringUtils.EMPTY;
}
} }
/** /**
@ -148,4 +146,44 @@ public class ComponentInfo implements Serializable {
return (StringUtils.isEmpty(componentManufacturer) return (StringUtils.isEmpty(componentManufacturer)
|| StringUtils.isEmpty(componentModel)); || StringUtils.isEmpty(componentModel));
} }
/**
* Equals for the component info that just uses this classes attributes.
* @param object the object to compare
* @return the boolean result
*/
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
ComponentInfo that = (ComponentInfo) object;
return Objects.equals(deviceName, that.deviceName)
&& Objects.equals(componentManufacturer,
that.componentManufacturer)
&& Objects.equals(componentModel, that.componentModel)
&& Objects.equals(componentSerial, that.componentSerial)
&& Objects.equals(componentRevision, that.componentRevision)
&& Objects.equals(componentClass, that.componentClass);
}
/**
* Returns a hash code that is associated with common fields for components.
* @return int value of the elements
*/
public int hashCommonElements() {
return Objects.hash(componentManufacturer, componentModel,
componentSerial, componentRevision, componentClass);
}
/**
* Hash method for the attributes of this class.
* @return int value that represents this class
*/
@Override
public int hashCode() {
return Objects.hash(deviceName, componentManufacturer,
componentModel, componentSerial, componentRevision,
componentClass);
}
} }

View File

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

View File

@ -28,8 +28,8 @@ import java.util.Objects;
* OS, and TPM information. * OS, and TPM information.
*/ */
@Log4j2 @Log4j2
@Getter
@NoArgsConstructor @NoArgsConstructor
@Getter
@Entity @Entity
public class DeviceInfoReport extends AbstractEntity implements Serializable { public class DeviceInfoReport extends AbstractEntity implements Serializable {
@ -196,7 +196,7 @@ public class DeviceInfoReport extends AbstractEntity implements Serializable {
return hardwareInfo; return hardwareInfo;
} }
private void setNetworkInfo(NetworkInfo networkInfo) { private void setNetworkInfo(final NetworkInfo networkInfo) {
if (networkInfo == null) { if (networkInfo == null) {
log.error("NetworkInfo cannot be null"); log.error("NetworkInfo cannot be null");
throw new NullPointerException("network info"); throw new NullPointerException("network info");
@ -204,7 +204,7 @@ public class DeviceInfoReport extends AbstractEntity implements Serializable {
this.networkInfo = networkInfo; this.networkInfo = networkInfo;
} }
private void setOSInfo(OSInfo osInfo) { private void setOSInfo(final OSInfo osInfo) {
if (osInfo == null) { if (osInfo == null) {
log.error("OSInfo cannot be null"); log.error("OSInfo cannot be null");
throw new NullPointerException("os info"); throw new NullPointerException("os info");
@ -212,7 +212,7 @@ public class DeviceInfoReport extends AbstractEntity implements Serializable {
this.osInfo = osInfo; this.osInfo = osInfo;
} }
private void setFirmwareInfo(FirmwareInfo firmwareInfo) { private void setFirmwareInfo(final FirmwareInfo firmwareInfo) {
if (firmwareInfo == null) { if (firmwareInfo == null) {
log.error("FirmwareInfo cannot be null"); log.error("FirmwareInfo cannot be null");
throw new NullPointerException("firmware info"); throw new NullPointerException("firmware info");
@ -220,7 +220,7 @@ public class DeviceInfoReport extends AbstractEntity implements Serializable {
this.firmwareInfo = firmwareInfo; this.firmwareInfo = firmwareInfo;
} }
private void setHardwareInfo(HardwareInfo hardwareInfo) { private void setHardwareInfo(final HardwareInfo hardwareInfo) {
if (hardwareInfo == null) { if (hardwareInfo == null) {
log.error("HardwareInfo cannot be null"); log.error("HardwareInfo cannot be null");
throw new NullPointerException("hardware info"); throw new NullPointerException("hardware info");
@ -228,7 +228,7 @@ public class DeviceInfoReport extends AbstractEntity implements Serializable {
this.hardwareInfo = hardwareInfo; this.hardwareInfo = hardwareInfo;
} }
private void setTPMInfo(TPMInfo tpmInfo) { private void setTPMInfo(final TPMInfo tpmInfo) {
this.tpmInfo = tpmInfo; this.tpmInfo = tpmInfo;
} }

View File

@ -51,6 +51,11 @@ public class AbstractProcessor {
@Getter @Getter
private PolicyRepository policyRepository; private PolicyRepository policyRepository;
/**
* Default constructor that sets main class fields.
* @param privateKey private key used for communication authentication
* @param validDays property value to set for issued certificates
*/
public AbstractProcessor(final PrivateKey privateKey, public AbstractProcessor(final PrivateKey privateKey,
final int validDays) { final int validDays) {
this.privateKey = privateKey; this.privateKey = privateKey;
@ -64,6 +69,7 @@ public class AbstractProcessor {
* @param endorsementCredential the endorsement credential * @param endorsementCredential the endorsement credential
* @param platformCredentials the set of platform credentials * @param platformCredentials the set of platform credentials
* @param deviceName The host name used in the subject alternative name * @param deviceName The host name used in the subject alternative name
* @param acaCertificate object used to create credential
* @return identity credential * @return identity credential
*/ */
protected X509Certificate generateCredential(final PublicKey publicKey, protected X509Certificate generateCredential(final PublicKey publicKey,
@ -159,7 +165,7 @@ public class AbstractProcessor {
* @param endorsementCredential an endorsement credential to check if platform credentials * @param endorsementCredential an endorsement credential to check if platform credentials
* exist * exist
* @param certificateRepository db connector from certificates * @param certificateRepository db connector from certificates
* @return the Set of Platform Credentials, if they exist, an empty set otherwise * @return the List of Platform Credentials, if they exist, an empty set otherwise
*/ */
protected List<PlatformCredential> parsePcsFromIdentityClaim( protected List<PlatformCredential> parsePcsFromIdentityClaim(
final ProvisionerTpm2.IdentityClaim identityClaim, final ProvisionerTpm2.IdentityClaim identityClaim,
@ -187,9 +193,11 @@ public class AbstractProcessor {
/** /**
* Gets the Endorsement Credential from the DB given the EK public key. * Gets the Endorsement Credential from the DB given the EK public key.
* @param ekPublicKey the EK public key * @param ekPublicKey the EK public key
* @param certificateRepository db store manager for certificates
* @return the Endorsement credential, if found, otherwise null * @return the Endorsement credential, if found, otherwise null
*/ */
private EndorsementCredential getEndorsementCredential(final PublicKey ekPublicKey, private EndorsementCredential getEndorsementCredential(
final PublicKey ekPublicKey,
final CertificateRepository certificateRepository) { final CertificateRepository certificateRepository) {
log.debug("Searching for endorsement credential based on public key: " + ekPublicKey); log.debug("Searching for endorsement credential based on public key: " + ekPublicKey);
@ -220,6 +228,7 @@ public class AbstractProcessor {
* Helper method to create an {@link IssuedAttestationCertificate} object, set its * Helper method to create an {@link IssuedAttestationCertificate} object, set its
* corresponding device and persist it. * corresponding device and persist it.
* *
* @param certificateRepository db store manager for certificates
* @param derEncodedAttestationCertificate the byte array representing the Attestation * @param derEncodedAttestationCertificate the byte array representing the Attestation
* certificate * certificate
* @param endorsementCredential the endorsement credential used to generate the AC * @param endorsementCredential the endorsement credential used to generate the AC

View File

@ -37,8 +37,11 @@ public class CertificateRequestProcessor extends AbstractProcessor {
/** /**
* Constructor. * Constructor.
* @param supplyChainValidationService object that is used to run provisioning
* @param certificateRepository db connector for all certificates. * @param certificateRepository db connector for all certificates.
* @param deviceRepository database connector for Devices. * @param deviceRepository database connector for Devices.
* @param privateKey private key used for communication authentication
* @param acaCertificate object used to create credential
* @param validDays int for the time in which a certificate is valid. * @param validDays int for the time in which a certificate is valid.
* @param tpm2ProvisionerStateRepository db connector for provisioner state. * @param tpm2ProvisionerStateRepository db connector for provisioner state.
*/ */
@ -97,7 +100,8 @@ public class CertificateRequestProcessor extends AbstractProcessor {
RSAPublicKey akPub = ProvisionUtils.parsePublicKey(claim.getAkPublicArea().toByteArray()); RSAPublicKey akPub = ProvisionUtils.parsePublicKey(claim.getAkPublicArea().toByteArray());
// Get Endorsement Credential if it exists or was uploaded // Get Endorsement Credential if it exists or was uploaded
EndorsementCredential endorsementCredential = parseEcFromIdentityClaim(claim, ekPub, certificateRepository); EndorsementCredential endorsementCredential = parseEcFromIdentityClaim(claim,
ekPub, certificateRepository);
// Get Platform Credentials if they exist or were uploaded // Get Platform Credentials if they exist or were uploaded
List<PlatformCredential> platformCredentials = parsePcsFromIdentityClaim(claim, List<PlatformCredential> platformCredentials = parsePcsFromIdentityClaim(claim,

View File

@ -3,18 +3,24 @@ package hirs.attestationca.persist.provision;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import hirs.attestationca.configuration.provisionerTpm2.ProvisionerTpm2; import hirs.attestationca.configuration.provisionerTpm2.ProvisionerTpm2;
import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentInfoRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository; import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.manager.PolicyRepository; import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository; import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository; import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.manager.TPM2ProvisionerStateRepository; import hirs.attestationca.persist.entity.manager.TPM2ProvisionerStateRepository;
import hirs.attestationca.persist.entity.tpm.TPM2ProvisionerState; import hirs.attestationca.persist.entity.tpm.TPM2ProvisionerState;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.Device; import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.persist.entity.userdefined.PolicySettings; import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest; import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary; import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo; import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo;
import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo; import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo;
import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo; import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo;
@ -29,6 +35,7 @@ import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.exceptions.IdentityProcessingException; import hirs.attestationca.persist.exceptions.IdentityProcessingException;
import hirs.attestationca.persist.provision.helper.ProvisionUtils; import hirs.attestationca.persist.provision.helper.ProvisionUtils;
import hirs.attestationca.persist.service.SupplyChainValidationService; import hirs.attestationca.persist.service.SupplyChainValidationService;
import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
import hirs.utils.HexUtils; import hirs.utils.HexUtils;
import hirs.utils.SwidResource; import hirs.utils.SwidResource;
import hirs.utils.enums.DeviceInfoEnums; import hirs.utils.enums.DeviceInfoEnums;
@ -70,17 +77,21 @@ public class IdentityClaimProcessor extends AbstractProcessor {
private SupplyChainValidationService supplyChainValidationService; private SupplyChainValidationService supplyChainValidationService;
private CertificateRepository certificateRepository; private CertificateRepository certificateRepository;
private ComponentResultRepository componentResultRepository;
private ComponentInfoRepository componentInfoRepository;
private ReferenceManifestRepository referenceManifestRepository; private ReferenceManifestRepository referenceManifestRepository;
private ReferenceDigestValueRepository referenceDigestValueRepository; private ReferenceDigestValueRepository referenceDigestValueRepository;
private DeviceRepository deviceRepository; private DeviceRepository deviceRepository;
private TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository; private TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository;
/** /**
* Constructor * Constructor.
*/ */
public IdentityClaimProcessor( public IdentityClaimProcessor(
final SupplyChainValidationService supplyChainValidationService, final SupplyChainValidationService supplyChainValidationService,
final CertificateRepository certificateRepository, final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository,
final ComponentInfoRepository componentInfoRepository,
final ReferenceManifestRepository referenceManifestRepository, final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository, final ReferenceDigestValueRepository referenceDigestValueRepository,
final DeviceRepository deviceRepository, final DeviceRepository deviceRepository,
@ -88,6 +99,8 @@ public class IdentityClaimProcessor extends AbstractProcessor {
final PolicyRepository policyRepository) { final PolicyRepository policyRepository) {
this.supplyChainValidationService = supplyChainValidationService; this.supplyChainValidationService = supplyChainValidationService;
this.certificateRepository = certificateRepository; this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository;
this.componentInfoRepository = componentInfoRepository;
this.referenceManifestRepository = referenceManifestRepository; this.referenceManifestRepository = referenceManifestRepository;
this.referenceDigestValueRepository = referenceDigestValueRepository; this.referenceDigestValueRepository = referenceDigestValueRepository;
this.deviceRepository = deviceRepository; this.deviceRepository = deviceRepository;
@ -187,7 +200,9 @@ public class IdentityClaimProcessor extends AbstractProcessor {
// Parse and save device info // Parse and save device info
Device device = processDeviceInfo(claim); Device device = processDeviceInfo(claim);
device.getDeviceInfo().setPaccorOutputString(claim.getPaccorOutput()); // device.getDeviceInfo().setPaccorOutputString(claim.getPaccorOutput());
handleDeviceComponents(device.getDeviceInfo().getNetworkInfo().getHostname(),
claim.getPaccorOutput());
// There are situations in which the claim is sent with no PCs // There are situations in which the claim is sent with no PCs
// or a PC from the tpm which will be deprecated // or a PC from the tpm which will be deprecated
// this is to check what is in the platform object and pull // this is to check what is in the platform object and pull
@ -203,9 +218,21 @@ public class IdentityClaimProcessor extends AbstractProcessor {
platformCredentials.addAll(tempList); platformCredentials.addAll(tempList);
} }
// store component results objects
for (PlatformCredential platformCredential : platformCredentials) {
List<ComponentResult> componentResults = componentResultRepository
.findByCertificateSerialNumberAndBoardSerialNumber(
platformCredential.getSerialNumber().toString(),
platformCredential.getPlatformSerial());
if (componentResults.isEmpty()) {
handlePlatformComponents(platformCredential);
}
}
// perform supply chain validation // perform supply chain validation
SupplyChainValidationSummary summary = supplyChainValidationService.validateSupplyChain( SupplyChainValidationSummary summary = supplyChainValidationService.validateSupplyChain(
endorsementCredential, platformCredentials, device); endorsementCredential, platformCredentials, device,
componentInfoRepository.findByDeviceName(device.getName()));
device.setSummaryId(summary.getId().toString()); device.setSummaryId(summary.getId().toString());
// update the validation result in the device // update the validation result in the device
AppraisalStatus.Status validationResult = summary.getOverallValidationResult(); AppraisalStatus.Status validationResult = summary.getOverallValidationResult();
@ -231,7 +258,12 @@ public class IdentityClaimProcessor extends AbstractProcessor {
log.info("Processing Device Info Report"); log.info("Processing Device Info Report");
// store device and device info report. // store device and device info report.
Device device = this.deviceRepository.findByName(deviceInfoReport.getNetworkInfo().getHostname()); Device device = null;
if (deviceInfoReport.getNetworkInfo() != null
&& deviceInfoReport.getNetworkInfo().getHostname() != null
&& !deviceInfoReport.getNetworkInfo().getHostname().isEmpty()) {
device = this.deviceRepository.findByName(deviceInfoReport.getNetworkInfo().getHostname());
}
if (device == null) { if (device == null) {
device = new Device(deviceInfoReport); device = new Device(deviceInfoReport);
} }
@ -302,7 +334,7 @@ public class IdentityClaimProcessor extends AbstractProcessor {
pcrValues = dv.getPcrslist().toStringUtf8(); pcrValues = dv.getPcrslist().toStringUtf8();
} }
// check for RIM Base and Support files, if they don't exists in the database, load them // check for RIM Base and Support files, if they don't exist in the database, load them
String defaultClientName = String.format("%s_%s", String defaultClientName = String.format("%s_%s",
dv.getHw().getManufacturer(), dv.getHw().getManufacturer(),
dv.getHw().getProductName()); dv.getHw().getProductName());
@ -314,7 +346,6 @@ public class IdentityClaimProcessor extends AbstractProcessor {
Pattern pattern = Pattern.compile("([^\\s]+(\\.(?i)(rimpcr|rimel|bin|log))$)"); Pattern pattern = Pattern.compile("([^\\s]+(\\.(?i)(rimpcr|rimel|bin|log))$)");
Matcher matcher; Matcher matcher;
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
// List<ReferenceManifest> listOfSavedRims = new LinkedList<>();
if (dv.getLogfileCount() > 0) { if (dv.getLogfileCount() > 0) {
for (ByteString logFile : dv.getLogfileList()) { for (ByteString logFile : dv.getLogfileList()) {
@ -424,11 +455,9 @@ public class IdentityClaimProcessor extends AbstractProcessor {
dbSupport.setUpdated(true); dbSupport.setUpdated(true);
dbSupport.setAssociatedRim(dbBaseRim.getId()); dbSupport.setAssociatedRim(dbBaseRim.getId());
this.referenceManifestRepository.save(dbSupport); this.referenceManifestRepository.save(dbSupport);
// listOfSavedRims.add(dbSupport);
} }
} }
this.referenceManifestRepository.save(dbBaseRim); this.referenceManifestRepository.save(dbBaseRim);
// listOfSavedRims.add(dbBaseRim);
} }
} }
@ -586,44 +615,66 @@ public class IdentityClaimProcessor extends AbstractProcessor {
log.error(String.format("Patching value does not exist (%s)", log.error(String.format("Patching value does not exist (%s)",
patchedValue)); patchedValue));
} else { } else {
/** // WIP - Until we get patch examples
* Until we get patch examples, this is WIP
*/
dbRdv.setPatched(true); dbRdv.setPatched(true);
} }
} }
} }
} catch (CertificateException cEx) { } catch (CertificateException | NoSuchAlgorithmException | IOException ex) {
log.error(cEx); log.error(ex);
} catch (NoSuchAlgorithmException noSaEx) {
log.error(noSaEx);
} catch (IOException ioEx) {
log.error(ioEx);
} }
} }
return true; return true;
} }
private int handlePlatformComponents(final Certificate certificate) {
PlatformCredential platformCredential;
int componentResults = 0;
if (certificate instanceof PlatformCredential) {
platformCredential = (PlatformCredential) certificate;
ComponentResult componentResult;
for (ComponentIdentifier componentIdentifier : platformCredential
.getComponentIdentifiers()) {
componentResult = new ComponentResult(platformCredential.getPlatformSerial(),
platformCredential.getSerialNumber().toString(),
platformCredential.getPlatformChainType(),
componentIdentifier);
componentResult.setFailedValidation(false);
componentResultRepository.save(componentResult);
componentResults++;
}
}
return componentResults;
}
private List<PlatformCredential> getPlatformCredentials(final CertificateRepository certificateRepository, private int handleDeviceComponents(final String hostName, final String paccorString) {
final EndorsementCredential ec) { int deviceComponents = 0 ;
List<PlatformCredential> credentials = null; Map<Integer, ComponentInfo> componentInfoMap = new HashMap<>();
try {
List<ComponentInfo> componentInfos = SupplyChainCredentialValidator
.getComponentInfoFromPaccorOutput(hostName, paccorString);
if (ec == null) { // check the DB for like component infos
log.warn("Cannot look for platform credential(s). Endorsement credential was null."); List<ComponentInfo> dbComponentInfos = this.componentInfoRepository.findByDeviceName(hostName);
} else { dbComponentInfos.stream().forEach((infos) -> {
log.debug("Searching for platform credential(s) based on holder serial number: " componentInfoMap.put(infos.hashCode(), infos);
+ ec.getSerialNumber()); });
credentials = certificateRepository.getByHolderSerialNumber(ec.getSerialNumber());
if (credentials == null || credentials.isEmpty()) { for (ComponentInfo componentInfo : dbComponentInfos) {
log.warn("No platform credential(s) found"); if (componentInfoMap.containsKey(componentInfo.hashCode())) {
} else { componentInfos.remove(componentInfo);
log.debug("Platform Credential(s) found: " + credentials.size());
} }
} }
return credentials; for (ComponentInfo componentInfo : componentInfos) {
this.componentInfoRepository.save(componentInfo);
}
} catch (IOException ioEx) {
log.warn("Error parsing paccor string");
}
return deviceComponents;
} }
} }

View File

@ -5,11 +5,8 @@ import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**

View File

@ -4,8 +4,6 @@ import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCred
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DEROctetString;
@ -42,13 +40,13 @@ public final class IssuedCertificateAttributeHelper {
/** /**
* Object Identifier TCPA at TPM ID Label. * Object Identifier TCPA at TPM ID Label.
*/ */
public final static ASN1ObjectIdentifier TCPA_AT_TPM_ID_LABEL = public static final ASN1ObjectIdentifier TCPA_AT_TPM_ID_LABEL =
new ASN1ObjectIdentifier(TPM_ID_LABEL_OID); new ASN1ObjectIdentifier(TPM_ID_LABEL_OID);
/** /**
* The extended key usage extension. * The extended key usage extension.
*/ */
public final static Extension EXTENDED_KEY_USAGE_EXTENSION; public static final Extension EXTENDED_KEY_USAGE_EXTENSION;
private final static ASN1ObjectIdentifier TCG_KP_AIK_CERTIFICATE_ATTRIBUTE = private static final ASN1ObjectIdentifier TCG_KP_AIK_CERTIFICATE_ATTRIBUTE =
new ASN1ObjectIdentifier("2.23.133.8.3"); new ASN1ObjectIdentifier("2.23.133.8.3");
static { static {

View File

@ -4,6 +4,7 @@ import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.entity.ArchivableEntity; import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.manager.CACredentialRepository; import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository; import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.PolicyRepository; import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository; import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
@ -14,14 +15,18 @@ import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.persist.entity.userdefined.PolicySettings; import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation; import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary; import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentAttributeResult;
import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements; import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest; import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.persist.enums.AppraisalStatus; import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.validation.PcrValidator; import hirs.attestationca.persist.validation.PcrValidator;
import hirs.attestationca.persist.validation.SupplyChainCredentialValidator; import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.Level;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -32,8 +37,7 @@ import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import org.apache.logging.log4j.Level;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL; import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS; import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
@ -47,9 +51,11 @@ public class SupplyChainValidationService {
private ReferenceManifestRepository referenceManifestRepository; private ReferenceManifestRepository referenceManifestRepository;
private ReferenceDigestValueRepository referenceDigestValueRepository; private ReferenceDigestValueRepository referenceDigestValueRepository;
private ComponentResultRepository componentResultRepository; private ComponentResultRepository componentResultRepository;
private ComponentAttributeRepository componentAttributeRepository;
private CertificateRepository certificateRepository; private CertificateRepository certificateRepository;
private SupplyChainValidationRepository supplyChainValidationRepository; private SupplyChainValidationRepository supplyChainValidationRepository;
private SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository; private SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository;
private UUID provisionSessionId;
/** /**
* Constructor. * Constructor.
@ -70,6 +76,7 @@ public class SupplyChainValidationService {
final PolicyRepository policyRepository, final PolicyRepository policyRepository,
final CertificateRepository certificateRepository, final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository, final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository,
final ReferenceManifestRepository referenceManifestRepository, final ReferenceManifestRepository referenceManifestRepository,
final SupplyChainValidationRepository supplyChainValidationRepository, final SupplyChainValidationRepository supplyChainValidationRepository,
final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository, final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository,
@ -78,6 +85,7 @@ public class SupplyChainValidationService {
this.policyRepository = policyRepository; this.policyRepository = policyRepository;
this.certificateRepository = certificateRepository; this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository; this.componentResultRepository = componentResultRepository;
this.componentAttributeRepository = componentAttributeRepository;
this.referenceManifestRepository = referenceManifestRepository; this.referenceManifestRepository = referenceManifestRepository;
this.supplyChainValidationRepository = supplyChainValidationRepository; this.supplyChainValidationRepository = supplyChainValidationRepository;
this.supplyChainValidationSummaryRepository = supplyChainValidationSummaryRepository; this.supplyChainValidationSummaryRepository = supplyChainValidationSummaryRepository;
@ -92,13 +100,16 @@ public class SupplyChainValidationService {
* @param ec The endorsement credential from the identity request. * @param ec The endorsement credential from the identity request.
* @param pcs The platform credentials from the identity request. * @param pcs The platform credentials from the identity request.
* @param device The device to be validated. * @param device The device to be validated.
* @param componentInfos list of components from the device
* @return A summary of the validation results. * @return A summary of the validation results.
*/ */
@SuppressWarnings("methodlength") @SuppressWarnings("methodlength")
public SupplyChainValidationSummary validateSupplyChain(final EndorsementCredential ec, public SupplyChainValidationSummary validateSupplyChain(final EndorsementCredential ec,
final List<PlatformCredential> pcs, final List<PlatformCredential> pcs,
final Device device) { final Device device,
final List<ComponentInfo> componentInfos) {
boolean acceptExpiredCerts = getPolicySettings().isExpiredCertificateValidationEnabled(); boolean acceptExpiredCerts = getPolicySettings().isExpiredCertificateValidationEnabled();
provisionSessionId = UUID.randomUUID();
PlatformCredential baseCredential = null; PlatformCredential baseCredential = null;
SupplyChainValidation platformScv = null; SupplyChainValidation platformScv = null;
SupplyChainValidation basePlatformScv = null; SupplyChainValidation basePlatformScv = null;
@ -205,6 +216,8 @@ public class SupplyChainValidationService {
null, Level.ERROR)); null, Level.ERROR));
} else { } else {
if (chkDeltas) { if (chkDeltas) {
// There are delta certificates, so the code need to build a new list of
// certificate components to then compare against the device component list
aes.addAll(basePlatformScv.getCertificatesUsed()); aes.addAll(basePlatformScv.getCertificatesUsed());
Iterator<PlatformCredential> it = pcs.iterator(); Iterator<PlatformCredential> it = pcs.iterator();
while (it.hasNext()) { while (it.hasNext()) {
@ -220,16 +233,23 @@ public class SupplyChainValidationService {
} }
} }
} else { } else {
// validate attributes for a single base platform certificate
aes.add(baseCredential); aes.add(baseCredential);
validations.remove(platformScv); validations.remove(platformScv);
// if there are no deltas, just check base credential // if there are no deltas, just check base credential
platformScv = ValidationService.evaluatePCAttributesStatus( platformScv = ValidationService.evaluatePCAttributesStatus(
baseCredential, device.getDeviceInfo(), ec, baseCredential, device.getDeviceInfo(), ec,
certificateRepository, componentResultRepository); certificateRepository, componentResultRepository,
componentAttributeRepository, componentInfos, provisionSessionId);
validations.add(new SupplyChainValidation( validations.add(new SupplyChainValidation(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL, SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
platformScv.getValidationResult(), aes, platformScv.getMessage())); platformScv.getValidationResult(), aes, platformScv.getMessage()));
} }
updateComponentStatus(componentResultRepository
.findByCertificateSerialNumberAndBoardSerialNumber(
baseCredential.getSerialNumber().toString(),
baseCredential.getPlatformSerial()));
} }
if (!attrErrorMessage.isEmpty()) { if (!attrErrorMessage.isEmpty()) {
//combine platform and platform attributes //combine platform and platform attributes
@ -252,7 +272,7 @@ public class SupplyChainValidationService {
log.info("The validation finished, summarizing..."); log.info("The validation finished, summarizing...");
// Generate validation summary, save it, and return it. // Generate validation summary, save it, and return it.
SupplyChainValidationSummary summary SupplyChainValidationSummary summary
= new SupplyChainValidationSummary(device, validations); = new SupplyChainValidationSummary(device, validations, provisionSessionId);
try { try {
supplyChainValidationSummaryRepository.save(summary); supplyChainValidationSummaryRepository.save(summary);
} catch (DBManagerException dbMEx) { } catch (DBManagerException dbMEx) {
@ -374,4 +394,25 @@ public class SupplyChainValidationService {
} }
return defaultSettings; return defaultSettings;
} }
/**
* If the platform attributes policy is enabled, this method updates the matched
* status for the component result. This is done so that the details page for the
* platform certificate highlights the title card red.
* @param componentResults list of associated component results
*/
private void updateComponentStatus(final List<ComponentResult> componentResults) {
List<ComponentAttributeResult> componentAttributeResults = componentAttributeRepository
.findByProvisionSessionId(provisionSessionId);
List<UUID> componentIdList = new ArrayList<>();
for (ComponentAttributeResult componentAttributeResult : componentAttributeResults) {
componentIdList.add(componentAttributeResult.getComponentId());
}
for (ComponentResult componentResult : componentResults) {
componentResult.setFailedValidation(componentIdList.contains(componentResult.getId()));
componentResultRepository.save(componentResult);
}
}
} }

View File

@ -3,6 +3,7 @@ package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.ArchivableEntity; import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.manager.CACredentialRepository; import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository; import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository; import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository; import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
@ -12,9 +13,9 @@ import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest; import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation; import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential; 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.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport; import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.enums.AppraisalStatus; import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.validation.CertificateAttributeScvValidator; import hirs.attestationca.persist.validation.CertificateAttributeScvValidator;
@ -37,6 +38,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
@Log4j2 @Log4j2
public class ValidationService { public class ValidationService {
@ -104,7 +106,10 @@ public class ValidationService {
final PlatformCredential pc, final DeviceInfoReport deviceInfoReport, final PlatformCredential pc, final DeviceInfoReport deviceInfoReport,
final EndorsementCredential ec, final EndorsementCredential ec,
final CertificateRepository certificateRepository, final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository) { final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository,
final List<ComponentInfo> componentInfos,
final UUID provisionSessionId) {
final SupplyChainValidation.ValidationType validationType final SupplyChainValidation.ValidationType validationType
= SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES; = SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES;
@ -116,7 +121,9 @@ public class ValidationService {
} }
log.info("Validating platform credential attributes"); log.info("Validating platform credential attributes");
AppraisalStatus result = CredentialValidator. AppraisalStatus result = CredentialValidator.
validatePlatformCredentialAttributes(pc, deviceInfoReport, ec); validatePlatformCredentialAttributes(pc, deviceInfoReport, ec,
componentResultRepository, componentAttributeRepository,
componentInfos, provisionSessionId);
switch (result.getAppStatus()) { switch (result.getAppStatus()) {
case PASS: case PASS:
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS, return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,
@ -126,10 +133,6 @@ public class ValidationService {
pc.setComponentFailures(result.getAdditionalInfo()); pc.setComponentFailures(result.getAdditionalInfo());
pc.setComponentFailureMessage(result.getMessage()); pc.setComponentFailureMessage(result.getMessage());
certificateRepository.save(pc); certificateRepository.save(pc);
for (ComponentResult componentResult
: CertificateAttributeScvValidator.getComponentResultList()) {
componentResultRepository.save(componentResult);
}
} }
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL, return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), pc, Level.WARN); result.getMessage(), pc, Level.WARN);

View File

@ -4,11 +4,14 @@ import com.github.marandus.pciid.model.Device;
import com.github.marandus.pciid.model.Vendor; import com.github.marandus.pciid.model.Vendor;
import com.github.marandus.pciid.service.PciIdsDatabase; import com.github.marandus.pciid.service.PciIdsDatabase;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentClass;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.asn1.ASN1UTF8String; import org.bouncycastle.asn1.ASN1UTF8String;
import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.DERUTF8String;
@ -23,6 +26,7 @@ import java.util.List;
/** /**
* Provide Java access to PCI IDs. * Provide Java access to PCI IDs.
*/ */
@Log4j2
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class PciIds { public final class PciIds {
/** /**
@ -52,6 +56,7 @@ public final class PciIds {
String dbFile = null; String dbFile = null;
for (final String path : PCI_IDS_PATH) { for (final String path : PCI_IDS_PATH) {
if ((new File(path)).exists()) { if ((new File(path)).exists()) {
log.info("PCI IDs file was found {}", path);
dbFile = path; dbFile = path;
break; break;
} }
@ -113,6 +118,23 @@ public final class PciIds {
return newList; return newList;
} }
/**
* Iterate through all components and translate PCI hardware IDs as necessary. It will only
* translate ComponentResults objects as it relies on Component Class information.
* @param componentResults List of ComponentResults.
* @return the translated list of ComponentResults.
*/
public static List<ComponentResult> translateResults(final List<ComponentResult> componentResults) {
List<ComponentResult> newList = new ArrayList<>();
if (componentResults != null && !componentResults.isEmpty()) {
for (final ComponentResult componentResult : componentResults) {
newList.add(translateResult(componentResult));
}
}
return newList;
}
/** /**
* Translate Vendor and Device IDs, if found, in ComponentIdentifierV2 objects. * Translate Vendor and Device IDs, if found, in ComponentIdentifierV2 objects.
* It will only translate ID values, any other value will pass through. * It will only translate ID values, any other value will pass through.
@ -149,6 +171,23 @@ public final class PciIds {
return newComponent; return newComponent;
} }
/**
* Translate Vendor and Device IDs, if found, in ComponentResult objects.
* It will only translate ID values, any other value will pass through.
* @param componentResult ComponentResult object.
* @return the translated ComponentResult object.
*/
public static ComponentResult translateResult(final ComponentResult componentResult) {
ComponentResult newComponent = null;
if (componentResult != null) {
newComponent = componentResult;
newComponent.setManufacturer(translateVendor(componentResult.getManufacturer()));
newComponent.setModel(translateDevice(componentResult.getManufacturer(),
componentResult.getModel()));
}
return newComponent;
}
/** /**
* Look up the vendor name from the PCI IDs list, if the input string contains an ID. * Look up the vendor name from the PCI IDs list, if the input string contains an ID.
* If any part of this fails, return the original manufacturer value. * If any part of this fails, return the original manufacturer value.
@ -166,6 +205,23 @@ public final class PciIds {
return manufacturer; return manufacturer;
} }
/**
* Look up the vendor name from the PCI IDs list, if the input string contains an ID.
* If any part of this fails, return the original manufacturer value.
* @param refManufacturer String, likely from a ComponentResult
* @return String with the discovered vendor name, or the original manufacturer value.
*/
public static String translateVendor(final String refManufacturer) {
String manufacturer = refManufacturer;
if (manufacturer != null && manufacturer.trim().matches("^[0-9A-Fa-f]{4}$")) {
Vendor ven = DB.findVendor(manufacturer.toLowerCase());
if (ven != null && !Strings.isNullOrEmpty(ven.getName())) {
manufacturer = ven.getName();
}
}
return manufacturer;
}
/** /**
* Look up the device name from the PCI IDs list, if the input strings contain IDs. * Look up the device name from the PCI IDs list, if the input strings contain IDs.
* The Device lookup requires the Vendor ID AND the Device ID to be valid values. * The Device lookup requires the Vendor ID AND the Device ID to be valid values.
@ -190,4 +246,28 @@ public final class PciIds {
} }
return model; return model;
} }
/**
* Look up the device name from the PCI IDs list, if the input strings contain IDs.
* The Device lookup requires the Vendor ID AND the Device ID to be valid values.
* If any part of this fails, return the original model value.
* @param refManufacturer String, likely from a ComponentResult
* @param refModel String, likely from a ComponentResult
* @return String with the discovered device name, or the original model value.
*/
public static String translateDevice(final String refManufacturer,
final String refModel) {
String model = refModel;
if (refManufacturer != null
&& model != null
&& refManufacturer.trim().matches("^[0-9A-Fa-f]{4}$")
&& model.trim().matches("^[0-9A-Fa-f]{4}$")) {
Device dev = DB.findDevice(refManufacturer.toLowerCase(),
model.toLowerCase());
if (dev != null && !Strings.isNullOrEmpty(dev.getName())) {
model = dev.getName();
}
}
return model;
}
} }

View File

@ -1,9 +1,12 @@
package hirs.attestationca.persist.validation; package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.ArchivableEntity; import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.manager.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation; import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult; import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentAttributeResult;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
@ -43,15 +46,7 @@ import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
@Log4j2 @Log4j2
public class CertificateAttributeScvValidator extends SupplyChainCredentialValidator { public class CertificateAttributeScvValidator extends SupplyChainCredentialValidator {
private static List<ComponentResult> componentResultList = new LinkedList<>(); private static final String LC_UNKNOWN = "unknown";
/**
* Getter for the list of components to verify.
* @return a collection of components
*/
public static List<ComponentResult> getComponentResultList() {
return Collections.unmodifiableList(componentResultList);
}
/** /**
* Checks if the delta credential's attributes are valid. * Checks if the delta credential's attributes are valid.
@ -97,7 +92,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
List<ComponentIdentifier> origPcComponents List<ComponentIdentifier> origPcComponents
= new LinkedList<>(basePlatformCredential.getComponentIdentifiers()); = new LinkedList<>(basePlatformCredential.getComponentIdentifiers());
return validateDeltaAttributesChainV2p0(deltaPlatformCredential.getId(), return validateDeltaAttributesChainV2p0(
deviceInfoReport, deltaMapping, origPcComponents); deviceInfoReport, deltaMapping, origPcComponents);
} }
@ -190,7 +185,6 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
+ " did not match the Certificate's Serial Number"; + " did not match the Certificate's Serial Number";
log.error(message); log.error(message);
status = new AppraisalStatus(FAIL, message); status = new AppraisalStatus(FAIL, message);
} }
} }
} }
@ -198,16 +192,23 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
return status; return status;
} }
/** /**
* Validates device info report against the new platform credential. * Validates device info report against the new platform credential.
* @param platformCredential the Platform Credential * @param platformCredential the Platform Credential
* @param deviceInfoReport the Device Info Report * @param deviceInfoReport the Device Info Report
* @param componentResultRepository db access to component result of mismatching
* @param componentAttributeRepository db access to component attribute match status
* @param componentInfos list of device components
* @param provisionSessionId UUID associated with the SCV Summary
* @return either PASS or FAIL * @return either PASS or FAIL
*/ */
public static AppraisalStatus validatePlatformCredentialAttributesV2p0( public static AppraisalStatus validatePlatformCredentialAttributesV2p0(
final PlatformCredential platformCredential, final PlatformCredential platformCredential,
final DeviceInfoReport deviceInfoReport) { final DeviceInfoReport deviceInfoReport,
final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository,
final List<ComponentInfo> componentInfos,
final UUID provisionSessionId) {
boolean passesValidation = true; boolean passesValidation = true;
StringBuilder resultMessage = new StringBuilder(); StringBuilder resultMessage = new StringBuilder();
@ -236,6 +237,8 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
passesValidation &= fieldValidation; passesValidation &= fieldValidation;
if (!isNotSpecifiedOrUnknown(platformCredential.getVersion())
&& !isNotSpecifiedOrUnknown(hardwareInfo.getVersion())) {
fieldValidation = requiredPlatformCredentialFieldIsNonEmptyAndMatches( fieldValidation = requiredPlatformCredentialFieldIsNonEmptyAndMatches(
"PlatformVersion", "PlatformVersion",
platformCredential.getVersion(), platformCredential.getVersion(),
@ -246,6 +249,11 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
} }
passesValidation &= fieldValidation; passesValidation &= fieldValidation;
} else {
log.warn("The Platform Certificate System version was {} and the reported Device System Information "
+ "version was {}, therefore this check is skipped...",
platformCredential.getVersion(), hardwareInfo.getVersion());
}
// check PlatformSerial against both system-serial-number and baseboard-serial-number // check PlatformSerial against both system-serial-number and baseboard-serial-number
fieldValidation = ( fieldValidation = (
@ -291,42 +299,86 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
// There is no need to do comparisons with components that are invalid because // There is no need to do comparisons with components that are invalid because
// they did not have a manufacturer or model. // they did not have a manufacturer or model.
List<ComponentIdentifier> validPcComponents = allPcComponents.stream() // List<ComponentIdentifier> validPcComponents = allPcComponents.stream()
.filter(identifier -> identifier.getComponentManufacturer() != null // .filter(identifier -> identifier.getComponentManufacturer() != null
&& identifier.getComponentModel() != null) // && identifier.getComponentModel() != null)
.collect(Collectors.toList()); // .collect(Collectors.toList());
String paccorOutputString = deviceInfoReport.getPaccorOutputString(); // String paccorOutputString = deviceInfoReport.getPaccorOutputString();
String unmatchedComponents; // String unmatchedComponents;
try {
List<ComponentInfo> componentInfoList // populate componentResults list
= getComponentInfoFromPaccorOutput(paccorOutputString); List<ComponentResult> componentResults = componentResultRepository
unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch( .findByCertificateSerialNumberAndBoardSerialNumber(
platformCredential.getId(), platformCredential.getSerialNumber().toString(),
validPcComponents, componentInfoList); platformCredential.getPlatformSerial());
fieldValidation &= unmatchedComponents.isEmpty(); // first create hash map based on hashCode
} catch (IOException e) { Map<Integer, List<ComponentInfo>> deviceHashMap = new HashMap<>();
final String baseErrorMessage = "Error parsing JSON output from PACCOR: "; componentInfos.stream().forEach((componentInfo) -> {
log.error(baseErrorMessage + e.toString()); List<ComponentInfo> innerList;
log.error("PACCOR output string:\n" + paccorOutputString); Integer compInfoHash = componentInfo.hashCommonElements();
return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage()); if (deviceHashMap.containsKey(compInfoHash)) {
innerList = deviceHashMap.get(compInfoHash);
innerList.add(componentInfo);
} else {
innerList = new ArrayList<>(0);
innerList.add(componentInfo);
}
deviceHashMap.put(compInfoHash, innerList);
});
// Look for hash code in device mapping
// if it exists, don't save the component
List<ComponentResult> remainingComponentResults = new ArrayList<>();
int numOfAttributes = 0;
for (ComponentResult componentResult : componentResults) {
if (!deviceHashMap.containsKey(componentResult.hashCommonElements())) {
// didn't find the component result in the hashed mapping
remainingComponentResults.add(componentResult);
}
}
if (!remainingComponentResults.isEmpty()) {
// continue down the options, move to a different method.
// create component class mapping to component info
Map<String, List<ComponentInfo>> componentDeviceMap = new HashMap<>();
componentInfos.stream().forEach((componentInfo) -> {
List<ComponentInfo> innerList;
String componentClass = componentInfo.getComponentClass();
if (componentDeviceMap.containsKey(componentClass)) {
innerList = componentDeviceMap.get(componentClass);
innerList.add(componentInfo);
} else {
innerList = new ArrayList<>(0);
innerList.add(componentInfo);
}
componentDeviceMap.put(componentClass, innerList);
});
List<ComponentInfo> componentClassInfo;
List<ComponentAttributeResult> attributeResults = new ArrayList<>();
for (ComponentResult componentResult : remainingComponentResults) {
componentClassInfo = componentDeviceMap.get(componentResult.getComponentClassValue());
if (componentClassInfo.size() == 1) {
attributeResults.addAll(generateComponentResults(componentClassInfo.get(0), componentResult));
} else {
attributeResults.addAll(findMismatchedValues(componentClassInfo, componentResult));
}
}
for (ComponentAttributeResult componentAttributeResult : attributeResults) {
componentAttributeResult.setProvisionSessionId(provisionSessionId);
componentAttributeRepository.save(componentAttributeResult);
fieldValidation &= componentAttributeResult.checkMatchedStatus();
}
numOfAttributes = attributeResults.size();
} }
StringBuilder additionalInfo = new StringBuilder(); StringBuilder additionalInfo = new StringBuilder();
if (!fieldValidation) { if (!remainingComponentResults.isEmpty()) {
resultMessage.append("There are unmatched components:\n"); resultMessage.append(String.format("There are %d components not matched%n",
resultMessage.append(unmatchedComponents); remainingComponentResults.size()));
resultMessage.append(String.format("\twith %d total attributes mismatched.",
// pass information of which ones failed in additionInfo numOfAttributes));
int counter = 0;
for (ComponentIdentifier ci : validPcComponents) {
counter++;
additionalInfo.append(String.format("%d;", ci.hashCode()));
}
if (counter > 0) {
additionalInfo.insert(0, "COMPID=");
additionalInfo.append(counter);
}
} }
passesValidation &= fieldValidation; passesValidation &= fieldValidation;
@ -338,6 +390,78 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
} }
} }
/**
* This method produces component attribute results for a single device that was found
* by component class.
* @param componentInfo the device object
* @param componentResult the certificate expected object
* @return a list of attribute match results
*/
private static List<ComponentAttributeResult> generateComponentResults(
final ComponentInfo componentInfo,
final ComponentResult componentResult) {
// there are instances of components with the same class (ie hard disks, memory)
List<ComponentAttributeResult> attributeResults = new ArrayList<>();
if (!componentInfo.getComponentManufacturer().equals(componentResult.getManufacturer())) {
attributeResults.add(new ComponentAttributeResult(componentResult.getId(),
componentResult.getManufacturer(), componentInfo.getComponentManufacturer()));
}
if (!componentInfo.getComponentModel().equals(componentResult.getModel())) {
attributeResults.add(new ComponentAttributeResult(componentResult.getId(),
componentResult.getModel(), componentInfo.getComponentModel()));
}
if (!componentInfo.getComponentSerial().equals(componentResult.getSerialNumber())) {
attributeResults.add(new ComponentAttributeResult(componentResult.getId(),
componentResult.getSerialNumber(), componentInfo.getComponentSerial()));
}
if (!componentInfo.getComponentRevision().equals(componentResult.getRevisionNumber())) {
attributeResults.add(new ComponentAttributeResult(componentResult.getId(),
componentResult.getRevisionNumber(), componentInfo.getComponentRevision()));
}
return attributeResults;
}
/**
* This method is called when there are multiple components on the device that match
* the certificate component's component class type and there is either a mismatch or
* a status of not found to be assigned.
* @param componentClassInfo list of device components with the same class type
* @param componentResult the certificate component that is mismatched
* @return a list of attribute results, if all 4 attributes are never matched, it is not found
*/
private static List<ComponentAttributeResult> findMismatchedValues(
final List<ComponentInfo> componentClassInfo,
final ComponentResult componentResult) {
// this list only has those of the same class type
Map<String, ComponentInfo> componentSerialMap = new HashMap<>();
componentClassInfo.stream().forEach((componentInfo) -> {
componentSerialMap.put(componentInfo.getComponentSerial(), componentInfo);
});
// see if the serial exists
ComponentInfo componentInfo = componentSerialMap.get(componentResult.getSerialNumber());
if (componentInfo != null && componentInfo.getComponentManufacturer()
.equals(componentResult.getManufacturer())) {
// the serial matched and the manufacturer, create attribute result and move on
return generateComponentResults(componentInfo, componentResult);
} else {
// didn't find based on serial
// look for highest match; otherwise ignore
// I already know serial doesn't match
for (ComponentInfo ci : componentClassInfo) {
if (ci.getComponentManufacturer().equals(componentResult.getManufacturer())
&& ci.getComponentModel().equals(componentResult.getModel())) {
return generateComponentResults(ci, componentResult);
}
}
}
return Collections.emptyList();
}
/** /**
* The main purpose of this method, the in process of validation, is to * The main purpose of this method, the in process of validation, is to
* pick out the changes that lead to the delta cert and make sure the changes * pick out the changes that lead to the delta cert and make sure the changes
@ -351,7 +475,6 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
*/ */
@SuppressWarnings("methodlength") @SuppressWarnings("methodlength")
static AppraisalStatus validateDeltaAttributesChainV2p0( static AppraisalStatus validateDeltaAttributesChainV2p0(
final UUID certificateId,
final DeviceInfoReport deviceInfoReport, final DeviceInfoReport deviceInfoReport,
final Map<PlatformCredential, SupplyChainValidation> deltaMapping, final Map<PlatformCredential, SupplyChainValidation> deltaMapping,
final List<ComponentIdentifier> origPcComponents) { final List<ComponentIdentifier> origPcComponents) {
@ -466,10 +589,11 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
String unmatchedComponents; String unmatchedComponents;
try { try {
// compare based on component class // compare based on component class
List<ComponentInfo> componentInfoList = getV2PaccorOutput(paccorOutputString); List<ComponentInfo> componentInfoList = getComponentInfoFromPaccorOutput(
deviceInfoReport.getNetworkInfo().getHostname(),
paccorOutputString);
// this is what I want to rewrite // this is what I want to rewrite
unmatchedComponents = validateV2PlatformCredentialAttributes( unmatchedComponents = validateV2PlatformCredentialAttributes(
certificateId,
baseCompList, baseCompList,
componentInfoList); componentInfoList);
fieldValidation &= unmatchedComponents.isEmpty(); fieldValidation &= unmatchedComponents.isEmpty();
@ -505,7 +629,6 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
} }
private static String validateV2PlatformCredentialAttributes( private static String validateV2PlatformCredentialAttributes(
final UUID certificateId,
final List<ComponentIdentifier> fullDeltaChainComponents, final List<ComponentIdentifier> fullDeltaChainComponents,
final List<ComponentInfo> allDeviceInfoComponents) { final List<ComponentInfo> allDeviceInfoComponents) {
ComponentIdentifierV2 ciV2; ComponentIdentifierV2 ciV2;
@ -521,7 +644,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
ciV2 = (ComponentIdentifierV2) cId; ciV2 = (ComponentIdentifierV2) cId;
if (cInfo.getComponentClass().contains( if (cInfo.getComponentClass().contains(
ciV2.getComponentClass().getComponentIdentifier()) ciV2.getComponentClass().getComponentIdentifier())
&& isMatch(certificateId, cId, cInfo)) { && isMatch(cId, cInfo)) {
subCompIdList.remove(cId); subCompIdList.remove(cId);
subCompInfoList.remove(cInfo); subCompInfoList.remove(cInfo);
} }
@ -716,10 +839,10 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
* **NEW** this is updated with just the unmatched components * **NEW** this is updated with just the unmatched components
* if there are any failures, otherwise it remains unchanged. * if there are any failures, otherwise it remains unchanged.
* @param allDeviceInfoComponents the device info report components * @param allDeviceInfoComponents the device info report components
* @return true if validation passes * @return passes if the returned value is empty, otherwise the components that are unmatched
* populate the string
*/ */
private static String validateV2p0PlatformCredentialComponentsExpectingExactMatch( private static String validateV2p0PlatformCredentialComponentsExpectingExactMatch(
final UUID certificateId,
final List<ComponentIdentifier> untrimmedPcComponents, final List<ComponentIdentifier> untrimmedPcComponents,
final List<ComponentInfo> allDeviceInfoComponents) { final List<ComponentInfo> allDeviceInfoComponents) {
// For each manufacturer listed in the platform credential, create two lists: // For each manufacturer listed in the platform credential, create two lists:
@ -791,7 +914,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
if (first.isPresent()) { if (first.isPresent()) {
ComponentInfo potentialMatch = first.get(); ComponentInfo potentialMatch = first.get();
if (isMatch(certificateId, pcComponent, potentialMatch)) { if (isMatch(pcComponent, potentialMatch)) {
pcComponentsFromManufacturer.remove(pcComponent); pcComponentsFromManufacturer.remove(pcComponent);
deviceInfoComponentsFromManufacturer.remove(potentialMatch); deviceInfoComponentsFromManufacturer.remove(potentialMatch);
} }
@ -819,7 +942,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
if (first.isPresent()) { if (first.isPresent()) {
ComponentInfo potentialMatch = first.get(); ComponentInfo potentialMatch = first.get();
if (isMatch(certificateId, pcComponent, potentialMatch)) { if (isMatch(pcComponent, potentialMatch)) {
pcComponentsFromManufacturer.remove(pcComponent); pcComponentsFromManufacturer.remove(pcComponent);
deviceInfoComponentsFromManufacturer.remove(potentialMatch); deviceInfoComponentsFromManufacturer.remove(potentialMatch);
} }
@ -833,7 +956,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
= deviceInfoComponentsFromManufacturer.iterator(); = deviceInfoComponentsFromManufacturer.iterator();
while (diComponentIter.hasNext()) { while (diComponentIter.hasNext()) {
ComponentInfo potentialMatch = diComponentIter.next(); ComponentInfo potentialMatch = diComponentIter.next();
if (isMatch(certificateId, ci, potentialMatch)) { if (isMatch(ci, potentialMatch)) {
pcComponentsFromManufacturer.remove(ci); pcComponentsFromManufacturer.remove(ci);
diComponentIter.remove(); diComponentIter.remove();
} }
@ -872,13 +995,11 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
/** /**
* Checks if the fields in the potentialMatch match the fields in the pcComponent, * Checks if the fields in the potentialMatch match the fields in the pcComponent,
* or if the relevant field in the pcComponent is empty. * or if the relevant field in the pcComponent is empty.
* @param certificateId the certificate id
* @param pcComponent the platform credential component * @param pcComponent the platform credential component
* @param potentialMatch the component info from a device info report * @param potentialMatch the component info from a device info report
* @return true if the fields match exactly (null is considered the same as an empty string) * @return true if the fields match exactly (null is considered the same as an empty string)
*/ */
private static boolean isMatch(final UUID certificateId, public static boolean isMatch(final ComponentIdentifier pcComponent,
final ComponentIdentifier pcComponent,
final ComponentInfo potentialMatch) { final ComponentInfo potentialMatch) {
boolean matchesSoFar = true; boolean matchesSoFar = true;
@ -887,49 +1008,24 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
pcComponent.getComponentManufacturer() pcComponent.getComponentManufacturer()
); );
if (matchesSoFar) {
componentResultList.add(new ComponentResult(certificateId, pcComponent.hashCode(),
potentialMatch.getComponentSerial(),
pcComponent.getComponentSerial().getString()));
}
matchesSoFar &= isMatchOrEmptyInPlatformCert( matchesSoFar &= isMatchOrEmptyInPlatformCert(
potentialMatch.getComponentModel(), potentialMatch.getComponentModel(),
pcComponent.getComponentModel() pcComponent.getComponentModel()
); );
if (matchesSoFar) {
componentResultList.add(new ComponentResult(certificateId, pcComponent.hashCode(),
potentialMatch.getComponentSerial(),
pcComponent.getComponentSerial().getString()));
}
matchesSoFar &= isMatchOrEmptyInPlatformCert( matchesSoFar &= isMatchOrEmptyInPlatformCert(
potentialMatch.getComponentSerial(), potentialMatch.getComponentSerial(),
pcComponent.getComponentSerial() pcComponent.getComponentSerial()
); );
if (matchesSoFar) {
componentResultList.add(new ComponentResult(certificateId, pcComponent.hashCode(),
potentialMatch.getComponentSerial(),
pcComponent.getComponentSerial().getString()));
}
matchesSoFar &= isMatchOrEmptyInPlatformCert( matchesSoFar &= isMatchOrEmptyInPlatformCert(
potentialMatch.getComponentRevision(), potentialMatch.getComponentRevision(),
pcComponent.getComponentRevision() pcComponent.getComponentRevision()
); );
if (matchesSoFar) {
componentResultList.add(new ComponentResult(certificateId, pcComponent.hashCode(),
potentialMatch.getComponentSerial(),
pcComponent.getComponentSerial().getString()));
}
return matchesSoFar; return matchesSoFar;
} }
/** /**
* Checks if the fields in the potentialMatch match the fields in the pcComponent, * Checks if the fields in the potentialMatch match the fields in the pcComponent,
* or if the relevant field in the pcComponent is empty. * or if the relevant field in the pcComponent is empty.
@ -1009,7 +1105,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
* @param platformSerialNumberDescription description of the serial number for logging purposes. * @param platformSerialNumberDescription description of the serial number for logging purposes.
* @param deviceInfoSerialNumbers the map of device info serial numbers * @param deviceInfoSerialNumbers the map of device info serial numbers
* (key = description, value = serial number) * (key = description, value = serial number)
* @return true if the platform serial number was found (case insensitive search), * @return true if the platform serial number was found (case-insensitive search),
* false otherwise * false otherwise
*/ */
private static boolean deviceInfoContainsPlatformSerialNumber( private static boolean deviceInfoContainsPlatformSerialNumber(
@ -1090,6 +1186,22 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
return false; return false;
} }
/**
* Per update to the provisioning via Issue 723, Not Specified and Unknown values
* are to be ignored.
* @param versionNumber string value of the device/platform version number
* @return true if they equal Not Specified or Unknown
*/
public static boolean isNotSpecifiedOrUnknown(final String versionNumber) {
if(versionNumber == null) {
return true;
}
String fieldValue = versionNumber.toLowerCase();
return fieldValue.equals(DeviceInfoEnums.NOT_SPECIFIED.toLowerCase())
|| fieldValue.equals(LC_UNKNOWN);
}
private static boolean platformCredentialFieldMatches( private static boolean platformCredentialFieldMatches(
final String platformCredentialFieldName, final String platformCredentialFieldName,
final String platformCredentialFieldValue, final String platformCredentialFieldValue,

View File

@ -1,7 +1,10 @@
package hirs.attestationca.persist.validation; package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.manager.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport; import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.enums.AppraisalStatus; import hirs.attestationca.persist.enums.AppraisalStatus;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
@ -14,6 +17,8 @@ import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.UUID;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.ERROR; 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.FAIL;
@ -26,7 +31,7 @@ public class CredentialValidator extends SupplyChainCredentialValidator {
* Checks if the endorsement credential is valid. * Checks if the endorsement credential is valid.
* *
* @param ec the endorsement credential to verify. * @param ec the endorsement credential to verify.
* @param trustStore trust store holding trusted trusted certificates. * @param trustStore trust store holding trusted certificates.
* @param acceptExpired whether or not to accept expired and not yet valid certificates * @param acceptExpired whether or not to accept expired and not yet valid certificates
* as valid. * as valid.
* @return the result of the validation. * @return the result of the validation.
@ -160,12 +165,19 @@ public class CredentialValidator extends SupplyChainCredentialValidator {
* serial number of the platform to be validated. * serial number of the platform to be validated.
* @param endorsementCredential The endorsement credential supplied from the same * @param endorsementCredential The endorsement credential supplied from the same
* identity request as the platform credential. * identity request as the platform credential.
* @param componentResultRepository db access to component result of mismatching
* @param componentAttributeRepository db access to component attribute match status
* @param componentInfos list of device components
* @return The result of the validation. * @return The result of the validation.
*/ */
public static AppraisalStatus validatePlatformCredentialAttributes( public static AppraisalStatus validatePlatformCredentialAttributes(
final PlatformCredential platformCredential, final PlatformCredential platformCredential,
final DeviceInfoReport deviceInfoReport, final DeviceInfoReport deviceInfoReport,
final EndorsementCredential endorsementCredential) { final EndorsementCredential endorsementCredential,
final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository,
final List<ComponentInfo> componentInfos,
final UUID provisionSessionId) {
final String baseErrorMessage = "Can't validate platform credential attributes without "; final String baseErrorMessage = "Can't validate platform credential attributes without ";
String message; String message;
if (platformCredential == null) { if (platformCredential == null) {
@ -180,6 +192,10 @@ public class CredentialValidator extends SupplyChainCredentialValidator {
message = baseErrorMessage + "an endorsement credential"; message = baseErrorMessage + "an endorsement credential";
return new AppraisalStatus(FAIL, message); return new AppraisalStatus(FAIL, message);
} }
if (componentInfos.isEmpty()) {
message = baseErrorMessage + "a list of device components";
return new AppraisalStatus(FAIL, message);
}
// Quick, early check if the platform credential references the endorsement credential // Quick, early check if the platform credential references the endorsement credential
if (!endorsementCredential.getSerialNumber() if (!endorsementCredential.getSerialNumber()
@ -192,7 +208,8 @@ public class CredentialValidator extends SupplyChainCredentialValidator {
String credentialType = platformCredential.getCredentialType(); String credentialType = platformCredential.getCredentialType();
if (PlatformCredential.CERTIFICATE_TYPE_2_0.equals(credentialType)) { if (PlatformCredential.CERTIFICATE_TYPE_2_0.equals(credentialType)) {
return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV2p0( return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV2p0(
platformCredential, deviceInfoReport); platformCredential, deviceInfoReport, componentResultRepository,
componentAttributeRepository, componentInfos, provisionSessionId);
} }
return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV1p2( return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV1p2(
platformCredential, deviceInfoReport); platformCredential, deviceInfoReport);

View File

@ -7,7 +7,6 @@ import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.CertException; import org.bouncycastle.cert.CertException;
import org.bouncycastle.cert.X509AttributeCertificateHolder; import org.bouncycastle.cert.X509AttributeCertificateHolder;
@ -32,7 +31,6 @@ import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -93,15 +91,13 @@ public class SupplyChainCredentialValidator {
} else if (trustStore.size() == 0) { } else if (trustStore.size() == 0) {
throw new SupplyChainValidatorException("Truststore is empty"); throw new SupplyChainValidatorException("Truststore is empty");
} }
} catch (KeyStoreException e) { } catch (KeyStoreException ksEx) {
log.error("Error accessing trust store: " + e.getMessage()); log.error("Error accessing trust store: " + ksEx.getMessage());
} }
try { try {
Set<X509Certificate> trustedCerts = new HashSet<>(); Set<X509Certificate> trustedCerts = new HashSet<>();
Enumeration<String> alias = trustStore.aliases(); Enumeration<String> alias = trustStore.aliases();
while (alias.hasMoreElements()) { while (alias.hasMoreElements()) {
trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement())); trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
} }
@ -111,8 +107,8 @@ public class SupplyChainCredentialValidator {
log.error("Cert chain could not be validated"); log.error("Cert chain could not be validated");
} }
return certChainValidated; return certChainValidated;
} catch (KeyStoreException e) { } catch (KeyStoreException ksEx) {
throw new SupplyChainValidatorException("Error with the trust store", e); throw new SupplyChainValidatorException("Error with the trust store", ksEx);
} }
} }
@ -139,8 +135,8 @@ public class SupplyChainCredentialValidator {
} else if (trustStore.size() == 0) { } else if (trustStore.size() == 0) {
throw new SupplyChainValidatorException("Truststore is empty"); throw new SupplyChainValidatorException("Truststore is empty");
} }
} catch (KeyStoreException e) { } catch (KeyStoreException ksEx) {
log.error("Error accessing trust store: " + e.getMessage()); log.error("Error accessing trust store: " + ksEx.getMessage());
} }
try { try {
@ -152,9 +148,9 @@ public class SupplyChainCredentialValidator {
} }
return validateCertChain(cert, trustedCerts).isEmpty(); return validateCertChain(cert, trustedCerts).isEmpty();
} catch (KeyStoreException e) { } catch (KeyStoreException ksEx) {
log.error("Error accessing keystore", e); log.error("Error accessing keystore", ksEx);
throw new SupplyChainValidatorException("Error with the trust store", e); throw new SupplyChainValidatorException("Error with the trust store", ksEx);
} }
} }
@ -277,11 +273,13 @@ public class SupplyChainCredentialValidator {
/** /**
* Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects. * Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
* @param hostName the host machine associated with the component
* @param paccorOutput the output from PACCOR's allcomoponents.sh * @param paccorOutput the output from PACCOR's allcomoponents.sh
* @return a list of ComponentInfo objects built from paccorOutput * @return a list of ComponentInfo objects built from paccorOutput
* @throws java.io.IOException if something goes wrong parsing the JSON * @throws java.io.IOException if something goes wrong parsing the JSON
*/ */
public static List<ComponentInfo> getComponentInfoFromPaccorOutput(final String paccorOutput) public static List<ComponentInfo> getComponentInfoFromPaccorOutput(final String hostName,
final String paccorOutput)
throws IOException { throws IOException {
List<ComponentInfo> componentInfoList = new ArrayList<>(); List<ComponentInfo> componentInfoList = new ArrayList<>();
@ -292,52 +290,32 @@ public class SupplyChainCredentialValidator {
= rootNode.findValue("COMPONENTS").elements(); = rootNode.findValue("COMPONENTS").elements();
while (jsonComponentNodes.hasNext()) { while (jsonComponentNodes.hasNext()) {
JsonNode next = jsonComponentNodes.next(); JsonNode next = jsonComponentNodes.next();
componentInfoList.add(new ComponentInfo(
List<JsonNode> compClassNodes = next.findValues("COMPONENTCLASS");
if (compClassNodes.isEmpty()) {
componentInfoList.add(new ComponentInfo(hostName,
getJSONNodeValueAsText(next, "MANUFACTURER"), getJSONNodeValueAsText(next, "MANUFACTURER"),
getJSONNodeValueAsText(next, "MODEL"), getJSONNodeValueAsText(next, "MODEL"),
getJSONNodeValueAsText(next, "SERIAL"), getJSONNodeValueAsText(next, "SERIAL"),
getJSONNodeValueAsText(next, "REVISION"))); getJSONNodeValueAsText(next, "REVISION")));
} } else {
} // version 2
String componentClass = StringUtils.EMPTY;
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) { for (JsonNode subNode : compClassNodes) {
componentClass = getJSONNodeValueAsText(subNode, componentClass = getJSONNodeValueAsText(subNode,
"COMPONENTCLASSVALUE"); "COMPONENTCLASSVALUE");
} }
ciList.add(new ComponentInfo(manufacturer, model, componentInfoList.add(new ComponentInfo(hostName,
serial, revision, componentClass)); getJSONNodeValueAsText(next, "MANUFACTURER"),
getJSONNodeValueAsText(next, "MODEL"),
getJSONNodeValueAsText(next, "SERIAL"),
getJSONNodeValueAsText(next, "REVISION"),
componentClass));
}
} }
} }
return ciList; return componentInfoList;
} }
private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) { private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) {
@ -498,10 +476,10 @@ public class SupplyChainCredentialValidator {
PublicKey key = cert.getPublicKey(); PublicKey key = cert.getPublicKey();
cert.verify(key); cert.verify(key);
return true; return true;
} catch (SignatureException | InvalidKeyException e) { } catch (SignatureException | InvalidKeyException ex) {
return false; return false;
} catch (CertificateException | NoSuchAlgorithmException | NoSuchProviderException e) { } catch (CertificateException | NoSuchAlgorithmException | NoSuchProviderException ex) {
log.error("Exception occurred while checking if cert is self-signed", e); log.error("Exception occurred while checking if cert is self-signed", ex);
return false; return false;
} }
} }

View File

@ -0,0 +1,757 @@
package hirs.attestationca.persist;
import com.google.protobuf.ByteString;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.provision.AbstractProcessor;
import hirs.attestationca.persist.provision.helper.IssuedCertificateAttributeHelper;
import hirs.attestationca.persist.provision.helper.ProvisionUtils;
import hirs.structs.elements.aca.SymmetricAttestation;
import hirs.structs.elements.tpm.AsymmetricPublicKey;
import hirs.structs.elements.tpm.EncryptionScheme;
import hirs.structs.elements.tpm.IdentityProof;
import hirs.structs.elements.tpm.StorePubKey;
import hirs.structs.elements.tpm.SymmetricKey;
import hirs.utils.HexUtils;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.ArrayUtils;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.test.util.ReflectionTestUtils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.MGF1ParameterSpec;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
/**
* Test suite for {@link AttestationCertificateAuthority}.
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // needed to use non-static BeforeAll
public class AttestationCertificateAuthorityTest {
/**
* This internal class handles setup for testing the function
* generateCredential() from class AbstractProcessor. Because the
* function is Protected and in a different package than the test,
* it cannot be accessed directly.
*/
@Nested
public class AccessAbstractProcessor extends AbstractProcessor {
/**
* Constructor.
*
* @param privateKey the private key of the ACA
* @param validDays int for the time in which a certificate is valid.
*/
public AccessAbstractProcessor(final PrivateKey privateKey,
final int validDays) {
super(privateKey, validDays);
}
/**
* Public wrapper for the protected function generateCredential(), to access for testing.
*
* @param publicKey cannot be null
* @param endorsementCredential the endorsement credential
* @param platformCredentials the set of platform credentials
* @param deviceName The host name used in the subject alternative name
* @param acaCertificate the aca certificate
* @return the generated X509 certificate
*/
public X509Certificate accessGenerateCredential(final PublicKey publicKey,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials,
final String deviceName,
final X509Certificate acaCertificate) {
return generateCredential(publicKey,
endorsementCredential,
platformCredentials,
deviceName,
acaCertificate);
}
}
// object in test
private AttestationCertificateAuthority aca;
private AccessAbstractProcessor abstractProcessor;
// test key pair
private KeyPair keyPair;
// length of IV used in PKI
private static final int ENCRYPTION_IV_LEN = 16;
// length of secret key used in PKI
private static final int SECRETKEY_LEN = 128;
private static final String EK_PUBLIC_PATH = "/tpm2/ek.pub";
private static final String AK_PUBLIC_PATH = "/tpm2/ak.pub";
private static final String AK_NAME_PATH = "/tpm2/ak.name";
private static final String TEST_NONCE_BLOB_PATH = "test/nonce.blob";
private static final String EK_MODULUS_HEX = "a3 b5 c2 1c 57 be 40 c4 3c 78 90 0d 00 81 01 78"
+ "13 ca 02 ec b6 75 89 60 ca 60 9b 10 b6 b4 d0 0b"
+ "4d e4 68 ad 01 a6 91 e2 56 20 5e cf 16 fe 77 ae"
+ "1f 13 d7 ac a1 91 0b 68 f6 07 cf c2 4b 5e c1 2c"
+ "4c fe 3a c9 62 7e 10 02 5b 33 c8 c2 1a cd 2e 7f"
+ "dd 7c 43 ac a9 5f b1 d6 07 56 4f 72 9b 0a 00 6c"
+ "f6 8d 23 a1 84 ca c1 7f 5a 8b ef 0e 23 11 90 00"
+ "30 f2 99 e9 94 59 c6 b0 fe b2 5c 0c c7 b4 76 69"
+ "6c f1 b7 d8 e5 60 d6 61 9f ab 7c 17 ce a4 74 6d"
+ "8c cd e6 9e 6e bb 64 52 a7 c3 bf ac 07 e8 5e 3e"
+ "ae eb dc c5 95 37 26 6a 5d a6 a2 12 52 fa 03 43"
+ "b2 62 2d 87 8c a7 06 8f d6 3f 63 b6 2d 73 c4 9d"
+ "9d d6 55 0e bb db b1 eb dd c5 4b 8f c3 17 cb 3b"
+ "c3 bf f6 7f 13 44 de 8e d7 b9 f1 a7 15 56 8f 6c"
+ "cd f2 4c 86 99 39 19 88 d3 4a 2f 38 c4 c4 37 39"
+ "85 6f 41 98 19 14 a4 1f 95 bc 04 ef 74 c2 0d f3";
private static final String AK_MODULUS_HEX = "d7 c9 f0 e3 ac 1b 4a 1e 3c 9d 2d 57 02 e9 2a 93"
+ "b0 c0 e1 50 af e4 61 11 31 73 a1 96 b8 d6 d2 1c"
+ "40 40 c8 a6 46 a4 10 4b d1 06 74 32 f6 e3 8a 55"
+ "1e 03 c0 3e cc 75 04 c6 44 88 b6 ad 18 c9 45 65"
+ "0d be c5 45 22 bd 24 ad 32 8c be 83 a8 9b 1b d9"
+ "e0 c8 d9 ec 14 67 55 1b fe 68 dd c7 f7 33 e4 cd"
+ "87 bd ba 9a 07 e7 74 eb 57 ef 80 9c 6d ee f9 35"
+ "52 67 36 e2 53 98 46 a5 4e 8f 17 41 8d ff eb bb"
+ "9c d2 b4 df 57 f8 7f 31 ef 2e 2d 6e 06 7f 05 ed"
+ "3f e9 6f aa b4 b7 5a f9 6d ba ff 2b 5e f7 c1 05"
+ "90 68 1f b6 4b 38 67 f7 92 d8 73 51 6e 08 19 ad"
+ "ca 35 48 a7 c1 fb cb 01 9a 28 03 c9 fe bb 49 2f"
+ "88 3f a1 e7 a8 69 f0 f8 e8 78 db d3 6d c5 80 8d"
+ "c2 e4 8a af 4b c2 ac 48 2a 44 63 6e 39 b0 8f dd"
+ "e4 b3 a3 f9 2a b1 c8 d9 3d 6b c4 08 b0 16 c4 e7"
+ "c7 2f f5 94 c6 43 3e ee 9b 8a da e7 31 d1 54 dd";
private static final String AK_NAME_HEX = "00 0b 6e 8f 79 1c 7e 16 96 1b 11 71 65 9c e0 cd"
+ "ae 0d 4d aa c5 41 be 58 89 74 67 55 96 c2 5e 38"
+ "e2 94";
/**
* Registers bouncy castle as a security provider. Normally the JEE container will handle this,
* but since the tests are not instantiating a container, have the unit test runner set up the
* provider.
*/
@BeforeAll
public void setupTests() throws Exception {
//BeforeSuite
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
//BeforeTest
aca = new AttestationCertificateAuthority(null, keyPair.getPrivate(),
null, null, null, null, null, null, null, 1,
null, null, null, null) {
};
abstractProcessor = new AccessAbstractProcessor(keyPair.getPrivate(), 1);
Security.addProvider(new BouncyCastleProvider());
}
/**
* Tests {@link AttestationCertificateAuthority#processIdentityClaimTpm2(byte[])}
* where the byte array is null. Expects an illegal argument exception to be thrown.
*/
@Test
public void testProcessIdentityClaimTpm2NullRequest() {
assertThrows(IllegalArgumentException.class, () ->
aca.processIdentityClaimTpm2(null));
}
/**
* Tests {@link AttestationCertificateAuthority#getPublicKey()}.
*/
@Test
public void testGetPublicKey() {
// encoded byte array to be returned by public key
byte[] encoded = new byte[]{0, 1, 0, 1, 0};
// create mocks for testing
X509Certificate acaCertificate = mock(X509Certificate.class);
PublicKey publicKey = mock(PublicKey.class);
// assign the aca certificate to the aca
ReflectionTestUtils.setField(aca, "acaCertificate", acaCertificate);
// return a mocked public key
when(acaCertificate.getPublicKey()).thenReturn(publicKey);
// return test byte array
when(publicKey.getEncoded()).thenReturn(encoded);
// assert what the ACA returns is as expected
assertArrayEquals(encoded, aca.getPublicKey());
// verify mock interactions
verify(acaCertificate).getPublicKey();
verify(publicKey).getEncoded();
// verify no other interactions with mocks
verifyNoMoreInteractions(acaCertificate, publicKey);
}
/**
* Tests {@link ProvisionUtils#decryptAsymmetricBlob(byte[],
* EncryptionScheme, PrivateKey)}.
*
* @throws Exception during aca processing
*/
@Test
public void testDecryptAsymmetricBlob() throws Exception {
// test encryption transformation
EncryptionScheme encryptionScheme = EncryptionScheme.PKCS1;
// test variables
byte[] expected = "test".getBytes(StandardCharsets.UTF_8);
// encrypt the expected value using same algorithm as the ACA.
byte[] encrypted = encryptBlob(expected, encryptionScheme.toString());
// perform the decryption and assert that the decrypted bytes equal the expected bytes
assertArrayEquals(expected, ProvisionUtils.decryptAsymmetricBlob(
encrypted, encryptionScheme, keyPair.getPrivate()));
}
/**
* Tests {@link ProvisionUtils#decryptSymmetricBlob(
* byte[], byte[], byte[], String)}.
*
* @throws Exception during aca processing
*/
@Test
public void testDecryptSymmetricBlob() throws Exception {
// test encryption transformation
String transformation = "AES/CBC/PKCS5Padding";
// test variables
byte[] expected = "test".getBytes(StandardCharsets.UTF_8);
// create a key generator to generate a "shared" secret
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(SECRETKEY_LEN);
// use some random bytes as the IV to encrypt and subsequently decrypt with
byte[] randomBytes = new byte[ENCRYPTION_IV_LEN];
// generate the random bytes
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.nextBytes(randomBytes);
// the shared secret
byte[] secretKey = keyGenerator.generateKey().getEncoded();
// encrypt the expected value with the private key being the shared secret
byte[] encrypted = encryptBlob(expected, secretKey, randomBytes, transformation);
// perform the decryption using the generated shared secret, random bytes as an IV, and the
// AES CBC transformation for the cipher. then assert the decrypted results are the same
// as our expected value.
assertArrayEquals(expected,
ProvisionUtils.decryptSymmetricBlob(encrypted, secretKey, randomBytes, transformation));
}
/**
* Tests {@link ProvisionUtils#generateSymmetricKey()}.
*/
@Test
public void testGenerateSymmetricKey() {
// perform the test
SymmetricKey symmetricKey = ProvisionUtils.generateSymmetricKey();
// assert the symmetric algorithm, scheme, and key size are all set appropriately
assertTrue(symmetricKey.getAlgorithmId() == 6);
assertTrue(symmetricKey.getEncryptionScheme() == 255);
assertTrue(symmetricKey.getKeySize() == symmetricKey.getKey().length);
}
private void assertTrue(final boolean b) {
}
/**
* Tests {@link ProvisionUtils#generateAsymmetricContents(
* byte[], byte[], PublicKey)}.
*
* @throws Exception during aca processing
*/
@Test
public void testGenerateAsymmetricContents() throws Exception {
// "encoded" identity proof (returned by struct converter)
byte[] identityProofEncoded = new byte[]{0, 0, 1, 1};
// generate a random session key to be used for encryption and decryption
byte[] sessionKey = new byte[ENCRYPTION_IV_LEN];
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.nextBytes(sessionKey);
// perform the test
byte[] result = ProvisionUtils.generateAsymmetricContents(identityProofEncoded,
sessionKey, keyPair.getPublic());
// decrypt the result
byte[] decryptedResult = decryptBlob(result);
// create a SHA1 digest of the identity key
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(identityProofEncoded);
// generate the digest
byte[] identityDigest = md.digest();
// the decrypted asymmetric contents should be the session key and a SHA-1 hash of the
// encoded identity proof.
byte[] expected = ArrayUtils.addAll(sessionKey, identityDigest);
// compare the two byte arrays
assertArrayEquals(expected, decryptedResult);
}
/**
* Tests {@link ProvisionUtils#generateAttestation(X509Certificate,
* SymmetricKey)}.
*
* @throws Exception during aca processing
*/
@Test
public void testGenerateAttestation() throws Exception {
// create some mocks for the unit tests
X509Certificate certificate = mock(X509Certificate.class);
SymmetricKey symmetricKey = mock(SymmetricKey.class);
// create a key generator to generate a secret key
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(SECRETKEY_LEN);
// obtain the key from the generator
byte[] secretKey = keyGenerator.generateKey().getEncoded();
// use our public key for encryption
when(symmetricKey.getKey()).thenReturn(secretKey);
// just use the existing public key for the credential
when(certificate.getEncoded()).thenReturn(keyPair.getPublic().getEncoded());
// perform the actual test
SymmetricAttestation attestation = ProvisionUtils.generateAttestation(certificate, symmetricKey);
// validate that the attestation is not null
assertNotNull(attestation);
// validate the attestation algorithm
assertNotNull(attestation.getAlgorithm());
assertTrue(attestation.getAlgorithm().getAlgorithmId() == 6);
assertTrue(attestation.getAlgorithm().getEncryptionScheme() == 0x1);
assertTrue(attestation.getAlgorithm().getSignatureScheme() == 0);
assertTrue(attestation.getAlgorithm().getParamsSize() == 0);
// validate the attestation credential
assertNotNull(attestation.getCredential());
// validate that the credential size is the size of the actual credential block
assertTrue(attestation.getCredential().length == attestation.getCredentialSize());
// create containers for the 2 parts of the credential
byte[] iv = new byte[ENCRYPTION_IV_LEN];
byte[] credential = new byte[attestation.getCredential().length - iv.length];
// siphon off the first 16 bytes for the IV
System.arraycopy(attestation.getCredential(), 0, iv, 0, iv.length);
// the rest is the actual encrypted credential
System.arraycopy(attestation.getCredential(), iv.length, credential, 0, credential.length);
// decrypt the credential
byte[] decrypted = decryptBlob(credential, secretKey, iv, "AES/CBC/PKCS5Padding");
// assert that the decrypted credential is our public key
assertArrayEquals(keyPair.getPublic().getEncoded(), decrypted);
// verify that the mocks were interacted with appropriately
verify(symmetricKey).getKey();
verify(certificate).getEncoded();
verifyNoMoreInteractions(certificate, symmetricKey);
}
/**
* Tests {@link AttestationCertificateAuthority#
* AttestationCertificateAuthority(SupplyChainValidationService, PrivateKey,
* X509Certificate, StructConverter, CertificateManager, DeviceRegister, int,
* DeviceManager, DBManager)}.
*
* @throws Exception during subject alternative name checking if cert formatting is bad
*/
@Test
public void testGenerateCredential() throws Exception {
// test variables
final String identityProofLabelString = "label";
byte[] identityProofLabel = identityProofLabelString.getBytes(StandardCharsets.UTF_8);
byte[] modulus = ((RSAPublicKey) keyPair.getPublic()).getModulus().toByteArray();
X500Principal principal = new X500Principal("CN=TEST, OU=TEST, O=TEST, C=TEST");
int validDays = 1;
// create mocks for testing
IdentityProof identityProof = mock(IdentityProof.class);
AsymmetricPublicKey asymmetricPublicKey = mock(AsymmetricPublicKey.class);
StorePubKey storePubKey = mock(StorePubKey.class);
X509Certificate acaCertificate = mock(X509Certificate.class);
// assign ACA fields
ReflectionTestUtils.setField(aca, "validDays", validDays);
ReflectionTestUtils.setField(aca, "acaCertificate", acaCertificate);
// prepare identity proof interactions
when(identityProof.getLabel()).thenReturn(identityProofLabel);
// prepare other mocks
when(acaCertificate.getSubjectX500Principal()).thenReturn(principal);
when(acaCertificate.getIssuerX500Principal()).thenReturn(principal);
// perform the test
X509Certificate certificate = abstractProcessor.accessGenerateCredential(keyPair.getPublic(),
null,
new LinkedList<PlatformCredential>(),
"exampleIdLabel",
acaCertificate);
// grab the modulus from the generate certificate
byte[] resultMod = ((RSAPublicKey) certificate.getPublicKey()).getModulus().toByteArray();
// today and tomorrow, when the certificate should be valid for
Calendar today = Calendar.getInstance();
Calendar tomorrow = Calendar.getInstance();
tomorrow.add(Calendar.DATE, 1);
// validate the certificate
assertTrue(certificate.getIssuerX500Principal().toString().contains("CN=TEST"));
assertTrue(certificate.getIssuerX500Principal().toString().contains("OU=TEST"));
assertTrue(certificate.getIssuerX500Principal().toString().contains("O=TEST"));
assertTrue(certificate.getIssuerX500Principal().toString().contains("C=TEST"));
// validate the format of the subject and subject alternative name
assertEquals("", certificate.getSubjectX500Principal().getName());
assertEquals("exampleIdLabel",
((X500Name) GeneralNames.fromExtensions(((TBSCertificate.getInstance(
certificate.getTBSCertificate()).getExtensions())), Extension.
subjectAlternativeName).getNames()[0].getName()).getRDNs(
IssuedCertificateAttributeHelper.TCPA_AT_TPM_ID_LABEL)[0].getFirst()
.getValue().toString());
assertArrayEquals(modulus, resultMod);
// obtain the expiration dates from the certificate
Calendar beforeDate = Calendar.getInstance();
Calendar afterDate = Calendar.getInstance();
beforeDate.setTime(certificate.getNotBefore());
afterDate.setTime(certificate.getNotAfter());
// assert the dates are set correctly
assertEquals(today.get(Calendar.DATE), beforeDate.get(Calendar.DATE));
assertEquals(tomorrow.get(Calendar.DATE), afterDate.get(Calendar.DATE));
// validate mock interactions
verify(acaCertificate).getSubjectX500Principal();
verifyNoMoreInteractions(identityProof, asymmetricPublicKey, storePubKey, acaCertificate);
}
/**
* Tests {@link ProvisionUtils#assemblePublicKey(byte[])}.
*/
@Test
public void testAssemblePublicKeyUsingByteArray() {
// obtain the expected modulus from the existing public key
final BigInteger modulus = ((RSAPublicKey) keyPair.getPublic()).getModulus();
// perform test
RSAPublicKey publicKey = (RSAPublicKey) ProvisionUtils.assemblePublicKey(modulus.toByteArray());
// assert that the exponent and the modulus are the same. the exponents should be the well
// known prime, 101
assertTrue(publicKey.getPublicExponent().equals(new BigInteger("010001", 16)));
assertTrue(publicKey.getModulus().equals(modulus));
}
/**
* Tests {@link ProvisionUtils#assemblePublicKey(String)}.
*/
@Test
public void testAssemblePublicKeyUsingHexEncodedString() {
// obtain the expected modulus from the existing public key
final BigInteger modulus = ((RSAPublicKey) keyPair.getPublic()).getModulus();
// encode our existing public key into hex
final String modulusString = Hex.encodeHexString(
((RSAPublicKey) keyPair.getPublic()).getModulus().toByteArray());
// perform test
RSAPublicKey publicKey = (RSAPublicKey) ProvisionUtils.assemblePublicKey(modulusString);
// assert that the exponent and the modulus are the same. the exponents should be the well
// known prime, 101.
assertTrue(publicKey.getPublicExponent().equals(new BigInteger("010001", 16)));
assertTrue(publicKey.getModulus().equals(modulus));
}
/**
* Tests parsing the EK from the TPM2 output file.
* @throws URISyntaxException incorrect resource path
* @throws IOException unable to read from file
*/
@Test
public void testParseEk() throws URISyntaxException, IOException {
Path ekPath = Paths.get(getClass().getResource(
EK_PUBLIC_PATH).toURI());
byte[] ekFile = Files.readAllBytes(ekPath);
RSAPublicKey ek = ProvisionUtils.parsePublicKey(ekFile);
assertTrue(ek.getPublicExponent().equals(new BigInteger("010001", 16)));
byte[] mod = ek.getModulus().toByteArray();
// big integer conversion is signed so it can add a 0 byte
if (mod[0] == 0) {
byte[] tmp = new byte[mod.length - 1];
System.arraycopy(mod, 1, tmp, 0, mod.length - 1);
mod = tmp;
}
String hex = HexUtils.byteArrayToHexString(mod);
String realMod = EK_MODULUS_HEX.replaceAll("\\s+", "");
assertEquals(realMod, hex);
}
/**
* Tests parsing the AK public key from the TPM2 output file.
* @throws URISyntaxException incorrect resource path
* @throws IOException unable to read from file
*/
@Test
public void testParseAk() throws URISyntaxException, IOException {
Path akPath = Paths.get(getClass().getResource(
AK_PUBLIC_PATH).toURI());
byte[] akFile = Files.readAllBytes(akPath);
RSAPublicKey ak = ProvisionUtils.parsePublicKey(akFile);
assertTrue(ak.getPublicExponent().equals(new BigInteger("010001", 16)));
byte[] mod = ak.getModulus().toByteArray();
// big integer conversion is signed so it can add a 0 byte
if (mod[0] == 0) {
byte[] tmp = new byte[mod.length - 1];
System.arraycopy(mod, 1, tmp, 0, mod.length - 1);
mod = tmp;
}
String hex = HexUtils.byteArrayToHexString(mod);
String realMod = AK_MODULUS_HEX.replaceAll("\\s+", "");
assertEquals(realMod, hex);
}
/**
* Tests parsing the AK name from the TPM2 output file.
* @throws URISyntaxException incorrect resource path
* @throws IOException unable to read from file
* @throws NoSuchAlgorithmException inavlid algorithm
*/
@Test
public void testGenerateAkName() throws URISyntaxException, IOException,
NoSuchAlgorithmException {
Path akNamePath = Paths.get(getClass().getResource(
AK_NAME_PATH).toURI());
byte[] akNameFileBytes = Files.readAllBytes(akNamePath);
String realHex = HexUtils.byteArrayToHexString(akNameFileBytes);
String realMod = AK_MODULUS_HEX.replaceAll("\\s+", "");
byte[] akName = ProvisionUtils.generateAkName(HexUtils.hexStringToByteArray(realMod));
String hex = HexUtils.byteArrayToHexString(akName);
String realName = AK_NAME_HEX.replaceAll("\\s+", "");
assertEquals(hex, realName);
assertEquals(hex, realHex);
}
/**
* Method to generate a make credential output file for use in manual testing. Feed to
* a TPM 2.0 or emulator using the activate credential command to ensure proper parsing.
* Must be performed manually. To use, copy the TPM's ek and ak into
* HIRS_AttestationCA/src/test/resources/tpm2/test/ and ensure the variables akPubPath
* and ekPubPath are correct. Your output file will be
* HIRS_AttestationCA/src/test/resources/tpm2/test/make.blob and the nonce used will be
* output as HIRS_AttestationCA/src/test/resources/tpm2/test/secret.blob
* @throws URISyntaxException invalid file path
* @throws IOException unable to read file
*/
@Disabled
@Test
public void testMakeCredential() throws URISyntaxException, IOException {
Path akPubPath = Paths.get(getClass().getResource(
AK_PUBLIC_PATH).toURI());
Path ekPubPath = Paths.get(getClass().getResource(
EK_PUBLIC_PATH).toURI());
byte[] ekPubFile = Files.readAllBytes(ekPubPath);
byte[] akPubFile = Files.readAllBytes(akPubPath);
RSAPublicKey ekPub = ProvisionUtils.parsePublicKey(ekPubFile);
RSAPublicKey akPub = ProvisionUtils.parsePublicKey(akPubFile);
// prepare the nonce and wrap it with keys
byte[] nonce = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
ByteString blob = ProvisionUtils.tpm20MakeCredential(ekPub, akPub, nonce);
Path resources = Objects.requireNonNull(Paths.get(Objects.requireNonNull(this.getClass().getResource(
"/").toURI()))
.getParent().getParent().getParent().getParent());
Path makeBlob = resources.resolve("src/test/resources/tpm2/test/make.blob");
Files.write(makeBlob, blob.toByteArray());
Path secretPath = resources.resolve("src/test/resources/tpm2/test/secret.blob");
Files.write(secretPath, nonce);
}
/**
* Test helper method that encrypts a blob using the specified transformation and the test key
* pair public key.
*
* @param blob to be encrypted
* @param transformation used by a cipher to encrypt
* @return encrypted blob
* @throws Exception during the encryption process
*/
private byte[] encryptBlob(final byte[] blob, final String transformation) throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(transformation);
// use our generated public key to encrypt
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
// return the cipher text
return cipher.doFinal(blob);
}
/**
* Test helper method that encrypts a blob using a shared key and IV using the specified
* transformation.
*
* @param blob to be encrypted
* @param key shared key
* @param iv to encrypt with
* @param transformation of the encryption cipher
* @return encrypted blob
* @throws Exception
*/
private byte[] encryptBlob(final byte[] blob, final byte[] key, final byte[] iv,
final String transformation) throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(transformation);
// generate a secret key specification using the key and AES.
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// create IV parameter for key specification
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// encrypt using the key specification with the generated IV
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
// return the cipher text
return cipher.doFinal(blob);
}
/**
* Test helper method to decrypt blobs.
*
* @param blob to be decrypted
* @return decrypted blob
* @throws Exception
*/
private byte[] decryptBlob(final byte[] blob) throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(EncryptionScheme.OAEP.toString());
OAEPParameterSpec spec = new OAEPParameterSpec("Sha1", "MGF1",
MGF1ParameterSpec.SHA1, new PSource.PSpecified("TCPA".getBytes(StandardCharsets.UTF_8)));
// use our generated public key to encrypt
cipher.init(Cipher.PRIVATE_KEY, keyPair.getPrivate(), spec);
// return the cipher text
return cipher.doFinal(blob);
}
/**
* Test helper method that decrypts a blob using a shared key and IV using the specified.
* transformation.
*
* @param blob to be decrypted
* @param key shared key
* @param iv to decrypt with
* @param transformation of the decryption cipher
* @return decrypted blob
* @throws Exception
*/
private byte[] decryptBlob(final byte[] blob, final byte[] key, final byte[] iv,
final String transformation) throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(transformation);
// generate a secret key specification using the key and AES
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// create IV parameter for key specification
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// encrypt using the key specification with the generated IV
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
// return the cipher text
return cipher.doFinal(blob);
}
}

View File

@ -1,12 +1,14 @@
package hirs.attestationca.persist.entity; package hirs.attestationca.persist.entity;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.IOException; import static org.junit.jupiter.api.Assertions.assertEquals;
import java.security.cert.CertificateException; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
/** /**
* Unit tests for the class <code>Appraiser</code>. * Unit tests for the class <code>Appraiser</code>.
@ -160,5 +162,4 @@ public final class AppraiserTest {
assertNotEquals(appraiser1.hashCode(), appraiser2.hashCode()); assertNotEquals(appraiser1.hashCode(), appraiser2.hashCode());
assertNotEquals(appraiser2.hashCode(), appraiser1.hashCode()); assertNotEquals(appraiser2.hashCode(), appraiser1.hashCode());
} }
} }

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity;

View File

@ -87,13 +87,16 @@ public class TPM2ProvisionerStateTest {
/** /**
* Test that {@link TPM2ProvisionerState#getTPM2ProvisionerState(TPM2ProvisionerStateRepository, byte[])} works. * Test that {@link TPM2ProvisionerState#getTPM2ProvisionerState(
* {@link TPM2ProvisionerState#getTPM2ProvisionerState(TPM2ProvisionerStateRepository, byte[])}, null is returned. * TPM2ProvisionerStateRepository, byte[])} works.
* {@link TPM2ProvisionerState#getTPM2ProvisionerState(
* TPM2ProvisionerStateRepository, byte[])}, null is returned.
* @throws IOException this will never happen * @throws IOException this will never happen
*/ */
@Test @Test
public final void testGetTPM2ProvisionerStateNominal() throws IOException { public final void testGetTPM2ProvisionerStateNominal() throws IOException {
TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository = mock(TPM2ProvisionerStateRepository.class); TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository =
mock(TPM2ProvisionerStateRepository.class);
byte[] nonce = new byte[32]; byte[] nonce = new byte[32];
byte[] identityClaim = new byte[360]; byte[] identityClaim = new byte[360];
random.nextBytes(nonce); random.nextBytes(nonce);
@ -112,12 +115,14 @@ public class TPM2ProvisionerStateTest {
/** /**
* Test that if a null is passed as a nonce to * Test that if a null is passed as a nonce to
* {@link TPM2ProvisionerState#getTPM2ProvisionerState(TPM2ProvisionerStateRepository, byte[])}, null is returned. * {@link TPM2ProvisionerState#getTPM2ProvisionerState(
* TPM2ProvisionerStateRepository, byte[])}, null is returned.
* @throws IOException this will never happen * @throws IOException this will never happen
*/ */
@Test @Test
public final void testGetTPM2ProvisionerStateNullNonce() throws IOException { public final void testGetTPM2ProvisionerStateNullNonce() throws IOException {
TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository = mock(TPM2ProvisionerStateRepository.class); TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository =
mock(TPM2ProvisionerStateRepository.class);
byte[] nonce = new byte[32]; byte[] nonce = new byte[32];
byte[] identityClaim = new byte[360]; byte[] identityClaim = new byte[360];
random.nextBytes(nonce); random.nextBytes(nonce);
@ -133,12 +138,14 @@ public class TPM2ProvisionerStateTest {
/** /**
* Test that if a nonce that is less than 8 bytes is passed to * Test that if a nonce that is less than 8 bytes is passed to
* {@link TPM2ProvisionerState#getTPM2ProvisionerState(TPM2ProvisionerStateRepository, byte[])}, null is returned. * {@link TPM2ProvisionerState#getTPM2ProvisionerState(
* TPM2ProvisionerStateRepository, byte[])}, null is returned.
* @throws IOException this will never happen * @throws IOException this will never happen
*/ */
@Test @Test
public final void testGetTPM2ProvisionerStateNonceTooSmall() throws IOException { public final void testGetTPM2ProvisionerStateNonceTooSmall() throws IOException {
TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository = mock(TPM2ProvisionerStateRepository.class); TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository =
mock(TPM2ProvisionerStateRepository.class);
byte[] nonce = new byte[32]; byte[] nonce = new byte[32];
byte[] identityClaim = new byte[360]; byte[] identityClaim = new byte[360];
random.nextBytes(nonce); random.nextBytes(nonce);

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity.tpm;

View File

@ -0,0 +1,313 @@
package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.ConformanceCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo;
import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo;
import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo;
import hirs.attestationca.persist.entity.userdefined.info.OSInfo;
import hirs.attestationca.persist.entity.userdefined.info.TPMInfo;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReportTest;
import hirs.attestationca.persist.enums.AppraisalStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* Class with definitions and functions common to multiple Userdefined Entity object tests.
*
*/
public class AbstractUserdefinedEntityTest {
/**
* Location of a test (fake) SGI intermediate CA certificate.
*/
public static final String FAKE_SGI_INT_CA_FILE = "/certificates/fakeSGIIntermediateCA.cer";
/**
* Location of a test (fake) Intel intermediate CA certificate.
*/
public static final String FAKE_INTEL_INT_CA_FILE =
"/certificates/fakeIntelIntermediateCA.cer";
/**
* Location of a test (fake) root CA certificate.
*/
public static final String FAKE_ROOT_CA_FILE = "/certificates/fakeRootCA.cer";
/**
* Hex-encoded subject key identifier for the FAKE_ROOT_CA_FILE.
*/
public static final String FAKE_ROOT_CA_SUBJECT_KEY_IDENTIFIER_HEX =
"58ec313a1699f94c1c8c4e2c6412402b258f0177";
/**
* Location of a test identity certificate.
*/
private static final String TEST_IDENTITY_CERT = "/tpm/sample_identity_cert.cer";
/**
* Location of a test platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_1 =
"/validation/platform_credentials/Intel_pc1.cer";
/**
* Location of another, slightly different platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_2 =
"/validation/platform_credentials/Intel_pc2.cer";
/**
* Location of another, slightly different platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_3 =
"/validation/platform_credentials/Intel_pc3.cer";
/**
* Platform cert with comma separated baseboard and chassis serial number.
*/
public static final String TEST_PLATFORM_CERT_4 =
"/validation/platform_credentials/Intel_pc4.pem";
/**
* Another platform cert with comma separated baseboard and chassis serial number.
*/
public static final String TEST_PLATFORM_CERT_5 =
"/validation/platform_credentials/Intel_pc5.pem";
/**
* Location of another, slightly different platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_6 =
"/validation/platform_credentials/TPM_INTC_Platform_Cert_RSA.txt";
private static final Logger LOGGER = LogManager.getLogger(DeviceInfoReportTest.class);
/**
* Dummy message for supply chain validation test.
*/
public static final String VALIDATION_MESSAGE = "Some message.";
/**
* Construct a test certificate from the given parameters.
*
* @param <T> the type of Certificate that will be created
* @param certificateClass the class of certificate to generate
* @param filename the location of the certificate to be used
* @return the newly-constructed Certificate
* @throws IOException if there is a problem constructing the test certificate
*/
public static <T extends ArchivableEntity> Certificate getTestCertificate(
final Class<T> certificateClass, final String filename)
throws IOException {
return getTestCertificate(certificateClass, filename, null, null);
}
/**
* Construct a test certificate from the given parameters.
*
* @param <T> the type of Certificate that will be created
* @param certificateClass the class of certificate to generate
* @param filename the location of the certificate to be used
* @param endorsementCredential the endorsement credentials (can be null)
* @param platformCredentials the platform credentials (can be null)
* @return the newly-constructed Certificate
* @throws IOException if there is a problem constructing the test certificate
*/
public static <T extends ArchivableEntity> Certificate getTestCertificate(
final Class<T> certificateClass, final String filename,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials)
throws IOException {
Path certPath;
try {
certPath = Paths.get(Objects.requireNonNull(
AbstractUserdefinedEntityTest.class.getResource(filename)).toURI());
// certPath = Paths.get(Objects.requireNonNull(
// CertificateTest.class.getResource(filename)).toURI());
} catch (URISyntaxException e) {
throw new IOException("Could not resolve path URI", e);
}
switch (certificateClass.getSimpleName()) {
case "CertificateAuthorityCredential":
return new CertificateAuthorityCredential(certPath);
case "ConformanceCredential":
return new ConformanceCredential(certPath);
case "EndorsementCredential":
return new EndorsementCredential(certPath);
case "PlatformCredential":
return new PlatformCredential(certPath);
case "IssuedAttestationCertificate":
return new IssuedAttestationCertificate(certPath,
endorsementCredential, platformCredentials);
default:
throw new IllegalArgumentException(
String.format("Unknown certificate class %s", certificateClass.getName())
);
}
}
/**
* Return a list of all test certificates.
*
* @return a list of all test certificates
* @throws IOException if there is a problem deserializing certificates
*/
public static List<ArchivableEntity> getAllTestCertificates() throws IOException {
return Arrays.asList(
getTestCertificate(CertificateAuthorityCredential.class, FAKE_SGI_INT_CA_FILE),
getTestCertificate(CertificateAuthorityCredential.class, FAKE_INTEL_INT_CA_FILE),
getTestCertificate(CertificateAuthorityCredential.class, FAKE_ROOT_CA_FILE)
);
}
/**
* Creates a DeviceInfoReport instance usable for testing.
*
* @return a test DeviceInfoReport
*/
public static DeviceInfoReport getTestDeviceInfoReport() {
return new DeviceInfoReport(
createTestNetworkInfo(), createTestOSInfo(), createTestFirmwareInfo(),
createTestHardwareInfo(), createTPMInfo()
);
}
/**
* Creates a test instance of NetworkInfo.
*
* @return network information for a fake device
*/
public static NetworkInfo createTestNetworkInfo() {
try {
final String hostname = "test.hostname";
final InetAddress ipAddress =
InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
final byte[] macAddress = new byte[] {11, 22, 33, 44, 55, 66};
return new NetworkInfo(hostname, ipAddress, macAddress);
} catch (UnknownHostException e) {
LOGGER.error("error occurred while creating InetAddress");
return null;
}
}
/**
* Creates a test instance of OSInfo.
*
* @return OS information for a fake device
*/
public static OSInfo createTestOSInfo() {
return new OSInfo("test os name", "test os version", "test os arch",
"test distribution", "test distribution release");
}
/**
* Creates a test instance of FirmwareInfo.
*
* @return Firmware information for a fake device
*/
public static FirmwareInfo createTestFirmwareInfo() {
return new FirmwareInfo("test bios vendor", "test bios version", "test bios release date");
}
/**
* Creates a test instance of HardwareInfo.
*
* @return Hardware information for a fake device
*/
public static HardwareInfo createTestHardwareInfo() {
return new HardwareInfo("test manufacturer", "test product name", "test version",
"test really long serial number with many characters", "test really long chassis "
+ "serial number with many characters",
"test really long baseboard serial number with many characters");
}
/**
* Creates a test instance of TPMInfo.
*
* @return TPM information for a fake device
*/
public static final TPMInfo createTPMInfo() {
final short num1 = 1;
final short num2 = 2;
final short num3 = 3;
final short num4 = 4;
return new TPMInfo("test os make", num1, num2, num3, num4,
getTestIdentityCertificate());
}
/**
* Creates a test identity certificate.
*
* @return the test X509 certificate
*/
public static X509Certificate getTestIdentityCertificate() {
X509Certificate certificateValue = null;
InputStream istream = null;
istream = AbstractUserdefinedEntityTest.class.getResourceAsStream(
TEST_IDENTITY_CERT
);
try {
if (istream == null) {
throw new FileNotFoundException(TEST_IDENTITY_CERT);
}
CertificateFactory cf = CertificateFactory.getInstance("X.509");
certificateValue = (X509Certificate) cf.generateCertificate(
istream);
} catch (Exception e) {
return null;
} finally {
if (istream != null) {
try {
istream.close();
} catch (IOException e) {
LOGGER.error("test certificate file could not be closed");
}
}
}
return certificateValue;
}
/**
* Construct a SupplyChainValidation for use in tests according to the provided parameters.
*
* @param type the type of validation
* @param result the appraisal result
* @param certificates the certificates related to this validation
* @return the resulting SupplyChainValidation object
*/
public static SupplyChainValidation getTestSupplyChainValidation(
final SupplyChainValidation.ValidationType type,
final AppraisalStatus.Status result,
final List<ArchivableEntity> certificates) {
return new SupplyChainValidation(
type,
result,
certificates,
VALIDATION_MESSAGE
);
}
}

View File

@ -1,6 +1,11 @@
package hirs.attestationca.persist.entity.userdefined; package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.ArchivableEntity; import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.ConformanceCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@ -14,12 +19,8 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import hirs.attestationca.persist.entity.userdefined.certificate.*;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -29,17 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
/** /**
* This class tests functionality of the {@link Certificate} class. * This class tests functionality of the {@link Certificate} class.
*/ */
public class CertificateTest { public class CertificateTest extends AbstractUserdefinedEntityTest {
/**
* Location of a test (fake) root CA certificate.
*/
public static final String FAKE_ROOT_CA_FILE = "/certificates/fakeRootCA.cer";
/**
* Location of a test (fake) Intel intermediate CA certificate.
*/
public static final String FAKE_INTEL_INT_CA_FILE =
"/certificates/fakeIntelIntermediateCA.cer";
/** /**
* Location of a test (fake) Intel intermediate CA certificate. * Location of a test (fake) Intel intermediate CA certificate.
@ -47,11 +38,6 @@ public class CertificateTest {
public static final String INTEL_INT_CA_FILE = public static final String INTEL_INT_CA_FILE =
"/validation/platform_credentials/intel_chain/root/intermediate2.cer"; "/validation/platform_credentials/intel_chain/root/intermediate2.cer";
/**
* Location of a test (fake) SGI intermediate CA certificate.
*/
public static final String FAKE_SGI_INT_CA_FILE = "/certificates/fakeSGIIntermediateCA.cer";
/** /**
* Location of another test self-signed certificate. * Location of another test self-signed certificate.
*/ */
@ -78,12 +64,6 @@ public class CertificateTest {
*/ */
public static final String GS_ROOT_CA = "/certificates/stMicroCaCerts/gstpmroot.crt"; public static final String GS_ROOT_CA = "/certificates/stMicroCaCerts/gstpmroot.crt";
/**
* Hex-encoded subject key identifier for the FAKE_ROOT_CA_FILE.
*/
public static final String FAKE_ROOT_CA_SUBJECT_KEY_IDENTIFIER_HEX =
"58ec313a1699f94c1c8c4e2c6412402b258f0177";
/** /**
* Location of a test STM endorsement credential. * Location of a test STM endorsement credential.
*/ */
@ -119,7 +99,8 @@ public class CertificateTest {
public void testConstructCertFromByteArray() throws IOException, URISyntaxException { public void testConstructCertFromByteArray() throws IOException, URISyntaxException {
Certificate certificate = new CertificateAuthorityCredential( Certificate certificate = new CertificateAuthorityCredential(
Files.readAllBytes( Files.readAllBytes(
Paths.get(Objects.requireNonNull(this.getClass().getResource(FAKE_ROOT_CA_FILE)).toURI()) Paths.get(Objects.requireNonNull(this.getClass().getResource(
FAKE_ROOT_CA_FILE)).toURI())
) )
); );
assertEquals( assertEquals(
@ -163,7 +144,8 @@ public class CertificateTest {
@Test @Test
public void testConstructCertFromPath() throws URISyntaxException, IOException { public void testConstructCertFromPath() throws URISyntaxException, IOException {
Certificate certificate = new CertificateAuthorityCredential( Certificate certificate = new CertificateAuthorityCredential(
Paths.get(Objects.requireNonNull(this.getClass().getResource(FAKE_ROOT_CA_FILE)).toURI()) Paths.get(Objects.requireNonNull(this.getClass().getResource(
FAKE_ROOT_CA_FILE)).toURI())
); );
assertEquals( assertEquals(
"CN=Fake Root CA", "CN=Fake Root CA",
@ -202,12 +184,12 @@ public class CertificateTest {
Certificate.CertificateType.X509_CERTIFICATE, Certificate.CertificateType.X509_CERTIFICATE,
getTestCertificate( getTestCertificate(
PlatformCredential.class, PlatformCredential.class,
PlatformCredentialTest.TEST_PLATFORM_CERT_3).getCertificateType()); TEST_PLATFORM_CERT_3).getCertificateType());
assertEquals( assertEquals(
Certificate.CertificateType.ATTRIBUTE_CERTIFICATE, Certificate.CertificateType.ATTRIBUTE_CERTIFICATE,
getTestCertificate( getTestCertificate(
PlatformCredential.class, PlatformCredential.class,
PlatformCredentialTest.TEST_PLATFORM_CERT_3).getCertificateType()); TEST_PLATFORM_CERT_3).getCertificateType());
} }
@ -220,7 +202,7 @@ public class CertificateTest {
@Test @Test
public void testImportPem() throws IOException { public void testImportPem() throws IOException {
Certificate platformCredential = getTestCertificate( Certificate platformCredential = getTestCertificate(
PlatformCredential.class, PlatformCredentialTest.TEST_PLATFORM_CERT_4 PlatformCredential.class, TEST_PLATFORM_CERT_4
); );
assertEquals( assertEquals(
@ -232,7 +214,7 @@ public class CertificateTest {
); );
platformCredential = getTestCertificate( platformCredential = getTestCertificate(
PlatformCredential.class, PlatformCredentialTest.TEST_PLATFORM_CERT_5 PlatformCredential.class, TEST_PLATFORM_CERT_5
); );
assertEquals( assertEquals(
@ -295,13 +277,12 @@ public class CertificateTest {
public void testX509AttributeCertificateParsing() throws IOException, URISyntaxException { public void testX509AttributeCertificateParsing() throws IOException, URISyntaxException {
Certificate platformCert = getTestCertificate( Certificate platformCert = getTestCertificate(
PlatformCredential.class, PlatformCredential.class,
PlatformCredentialTest.TEST_PLATFORM_CERT_3 TEST_PLATFORM_CERT_3
); );
X509AttributeCertificateHolder attrCertHolder = new X509AttributeCertificateHolder( X509AttributeCertificateHolder attrCertHolder = new X509AttributeCertificateHolder(
Files.readAllBytes(Paths.get(Objects.requireNonNull(this.getClass().getResource( Files.readAllBytes(Paths.get(Objects.requireNonNull(this.getClass().getResource(
PlatformCredentialTest.TEST_PLATFORM_CERT_3 TEST_PLATFORM_CERT_3)).toURI()))
)).toURI()))
); );
assertEquals( assertEquals(
@ -330,7 +311,7 @@ public class CertificateTest {
public void testX509AttributeCertificateParsingExtended() public void testX509AttributeCertificateParsingExtended()
throws IOException, URISyntaxException { throws IOException, URISyntaxException {
Certificate platformCert = getTestCertificate( Certificate platformCert = getTestCertificate(
PlatformCredential.class, PlatformCredentialTest.TEST_PLATFORM_CERT_6); PlatformCredential.class, TEST_PLATFORM_CERT_6);
assertEquals("https://trustedservices.intel.com/" assertEquals("https://trustedservices.intel.com/"
+ "content/TSC/certs/TSC_IssuingCAIKGF_TEST.cer\n", + "content/TSC/certs/TSC_IssuingCAIKGF_TEST.cer\n",
@ -428,11 +409,13 @@ public class CertificateTest {
assertEquals( assertEquals(
new CertificateAuthorityCredential( new CertificateAuthorityCredential(
Paths.get(Objects.requireNonNull(this.getClass().getResource(FAKE_ROOT_CA_FILE)).toURI()) Paths.get(Objects.requireNonNull(this.getClass().getResource(
FAKE_ROOT_CA_FILE)).toURI())
), ),
new CertificateAuthorityCredential( new CertificateAuthorityCredential(
Files.readAllBytes( Files.readAllBytes(
Paths.get(Objects.requireNonNull(this.getClass().getResource(FAKE_ROOT_CA_FILE)).toURI()) Paths.get(Objects.requireNonNull(this.getClass().getResource(
FAKE_ROOT_CA_FILE)).toURI())
) )
) )
); );
@ -489,11 +472,13 @@ public class CertificateTest {
assertEquals( assertEquals(
new CertificateAuthorityCredential( new CertificateAuthorityCredential(
Paths.get(Objects.requireNonNull(this.getClass().getResource(FAKE_ROOT_CA_FILE)).toURI()) Paths.get(Objects.requireNonNull(this.getClass().getResource(
FAKE_ROOT_CA_FILE)).toURI())
).hashCode(), ).hashCode(),
new CertificateAuthorityCredential( new CertificateAuthorityCredential(
Files.readAllBytes( Files.readAllBytes(
Paths.get(Objects.requireNonNull(this.getClass().getResource(FAKE_ROOT_CA_FILE)).toURI()) Paths.get(Objects.requireNonNull(this.getClass().getResource(
FAKE_ROOT_CA_FILE)).toURI())
) )
).hashCode() ).hashCode()
); );
@ -520,79 +505,6 @@ public class CertificateTest {
return getTestCertificate(CertificateAuthorityCredential.class, filename); return getTestCertificate(CertificateAuthorityCredential.class, filename);
} }
/**
* Construct a test certificate from the given parameters.
*
* @param <T> the type of Certificate that will be created
* @param certificateClass the class of certificate to generate
* @param filename the location of the certificate to be used
* @return the newly-constructed Certificate
* @throws IOException if there is a problem constructing the test certificate
*/
public static <T extends ArchivableEntity> Certificate getTestCertificate(
final Class<T> certificateClass, final String filename)
throws IOException {
return getTestCertificate(certificateClass, filename, null, null);
}
/**
* Construct a test certificate from the given parameters.
*
* @param <T> the type of Certificate that will be created
* @param certificateClass the class of certificate to generate
* @param filename the location of the certificate to be used
* @param endorsementCredential the endorsement credentials (can be null)
* @param platformCredentials the platform credentials (can be null)
* @return the newly-constructed Certificate
* @throws IOException if there is a problem constructing the test certificate
*/
public static <T extends ArchivableEntity> Certificate getTestCertificate(
final Class<T> certificateClass, final String filename,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials)
throws IOException {
Path certPath;
try {
certPath = Paths.get(Objects.requireNonNull(CertificateTest.class.getResource(filename)).toURI());
} catch (URISyntaxException e) {
throw new IOException("Could not resolve path URI", e);
}
switch (certificateClass.getSimpleName()) {
case "CertificateAuthorityCredential":
return new CertificateAuthorityCredential(certPath);
case "ConformanceCredential":
return new ConformanceCredential(certPath);
case "EndorsementCredential":
return new EndorsementCredential(certPath);
case "PlatformCredential":
return new PlatformCredential(certPath);
case "IssuedAttestationCertificate":
return new IssuedAttestationCertificate(certPath,
endorsementCredential, platformCredentials);
default:
throw new IllegalArgumentException(
String.format("Unknown certificate class %s", certificateClass.getName())
);
}
}
/**
* Return a list of all test certificates.
*
* @return a list of all test certificates
* @throws IOException if there is a problem deserializing certificates
*/
public static List<ArchivableEntity> getAllTestCertificates() throws IOException {
return Arrays.asList(
getTestCertificate(CertificateAuthorityCredential.class, FAKE_SGI_INT_CA_FILE),
getTestCertificate(CertificateAuthorityCredential.class, FAKE_INTEL_INT_CA_FILE),
getTestCertificate(CertificateAuthorityCredential.class, FAKE_ROOT_CA_FILE)
);
}
private static X509Certificate readX509Certificate(final String resourceName) private static X509Certificate readX509Certificate(final String resourceName)
throws IOException { throws IOException {
@ -603,8 +515,9 @@ public class CertificateTest {
throw new IOException("Cannot get X509 CertificateFactory instance", e); throw new IOException("Cannot get X509 CertificateFactory instance", e);
} }
try (FileInputStream certInputStream = new FileInputStream( try (FileInputStream certInputStream = new FileInputStream(Paths.get(
Paths.get(Objects.requireNonNull(CertificateTest.class.getResource(resourceName)).toURI()).toFile() Objects.requireNonNull(CertificateTest.class.getResource(
resourceName)).toURI()).toFile()
)) { )) {
return (X509Certificate) cf.generateCertificate(certInputStream); return (X509Certificate) cf.generateCertificate(certInputStream);
} catch (CertificateException | URISyntaxException e) { } catch (CertificateException | URISyntaxException e) {

View File

@ -1,7 +1,6 @@
package hirs.attestationca.persist.entity.userdefined; package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport; import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReportTest;
import hirs.attestationca.persist.enums.AppraisalStatus; import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.enums.HealthStatus; import hirs.attestationca.persist.enums.HealthStatus;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -14,19 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
* This is the test class for the <code>Device</code> class. * This is the test class for the <code>Device</code> class.
* *
*/ */
public final class DeviceTest { public final class DeviceTest extends AbstractUserdefinedEntityTest {
/**
* Utility method for getting a <code>Device</code> that can be used for
* testing.
*
* @param name name for the <code>Device</code>
*
* @return device
*/
public static Device getTestDevice(final String name) {
final DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport();
return new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null);
}
/** /**
* Tests that the device constructor can take a name. * Tests that the device constructor can take a name.
@ -34,7 +21,9 @@ public final class DeviceTest {
@Test @Test
public void testDevice() { public void testDevice() {
final String name = "my-laptop"; final String name = "my-laptop";
final Device device = new Device(name, null, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null , null); final Device device = new Device(name, null, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
assertNotNull(device); assertNotNull(device);
} }
@ -45,8 +34,10 @@ public final class DeviceTest {
@Test @Test
public void testDeviceNameAndInfo() { public void testDeviceNameAndInfo() {
final String name = "my-laptop"; final String name = "my-laptop";
final DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
} }
/** /**
@ -56,7 +47,9 @@ public final class DeviceTest {
public void testDeviceNameAndNullInfo() { public void testDeviceNameAndNullInfo() {
final String name = "my-laptop"; final String name = "my-laptop";
final DeviceInfoReport deviceInfo = null; final DeviceInfoReport deviceInfo = null;
new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
} }
/** /**
@ -65,8 +58,10 @@ public final class DeviceTest {
@Test @Test
public void testGetDeviceInfo() { public void testGetDeviceInfo() {
final String name = "my-laptop"; final String name = "my-laptop";
final DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
assertEquals(deviceInfo, device.getDeviceInfo()); assertEquals(deviceInfo, device.getDeviceInfo());
} }
@ -76,9 +71,11 @@ public final class DeviceTest {
@Test @Test
public void testSetDeviceInfo() { public void testSetDeviceInfo() {
final String name = "my-laptop"; final String name = "my-laptop";
final Device device = new Device(name, null, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device(name, null, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
assertNull(device.getDeviceInfo()); assertNull(device.getDeviceInfo());
final DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
device.setDeviceInfo(deviceInfo); device.setDeviceInfo(deviceInfo);
assertEquals(deviceInfo, device.getDeviceInfo()); assertEquals(deviceInfo, device.getDeviceInfo());
} }
@ -89,8 +86,10 @@ public final class DeviceTest {
@Test @Test
public void testSetNullDeviceInfo() { public void testSetNullDeviceInfo() {
final String name = "my-laptop"; final String name = "my-laptop";
final DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
assertEquals(deviceInfo, device.getDeviceInfo()); assertEquals(deviceInfo, device.getDeviceInfo());
device.setDeviceInfo(null); device.setDeviceInfo(null);
assertNull(device.getDeviceInfo()); assertNull(device.getDeviceInfo());
@ -102,8 +101,10 @@ public final class DeviceTest {
@Test @Test
public void testNotNullLastReportTimeStamp() { public void testNotNullLastReportTimeStamp() {
final String name = "my-laptop"; final String name = "my-laptop";
final DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
assertNotNull(device.getLastReportTimestamp()); assertNotNull(device.getLastReportTimestamp());
} }
@ -112,7 +113,9 @@ public final class DeviceTest {
*/ */
@Test @Test
public void testSetHealthStatus() { public void testSetHealthStatus() {
final Device device = new Device("test-device", null, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device("test-device", null, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
device.setHealthStatus(HealthStatus.TRUSTED); device.setHealthStatus(HealthStatus.TRUSTED);
assertEquals(HealthStatus.TRUSTED, device.getHealthStatus()); assertEquals(HealthStatus.TRUSTED, device.getHealthStatus());
} }
@ -124,9 +127,13 @@ public final class DeviceTest {
public void testDeviceEquals() { public void testDeviceEquals() {
final String name = "my-laptop"; final String name = "my-laptop";
final String otherName = "my-laptop"; final String otherName = "my-laptop";
final DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN,
final Device other = new Device(otherName, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
final Device other = new Device(otherName, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
assertEquals(device, other); assertEquals(device, other);
} }
@ -136,8 +143,10 @@ public final class DeviceTest {
@Test @Test
public void testGetDefaultSupplyChainStatus() { public void testGetDefaultSupplyChainStatus() {
String name = "my-laptop"; String name = "my-laptop";
DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
assertEquals(AppraisalStatus.Status.UNKNOWN, device.getSupplyChainValidationStatus()); assertEquals(AppraisalStatus.Status.UNKNOWN, device.getSupplyChainValidationStatus());
} }
@ -147,8 +156,10 @@ public final class DeviceTest {
@Test @Test
public void testSetAndGetSupplyChainStatus() { public void testSetAndGetSupplyChainStatus() {
String name = "my-laptop"; String name = "my-laptop";
DeviceInfoReport deviceInfo = DeviceInfoReportTest.getTestReport(); final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN, AppraisalStatus.Status.UNKNOWN, null, false, null, null); final Device device = new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null, false,
null, null);
device.setSupplyChainValidationStatus(AppraisalStatus.Status.PASS); device.setSupplyChainValidationStatus(AppraisalStatus.Status.PASS);
assertEquals(AppraisalStatus.Status.PASS, device.getSupplyChainValidationStatus()); assertEquals(AppraisalStatus.Status.PASS, device.getSupplyChainValidationStatus());
} }

View File

@ -0,0 +1,54 @@
package hirs.attestationca.persist.entity.userdefined;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.jupiter.api.Test;
/**
* Unit test class for PolicySettings.
*/
public class PolicySettingsTest {
/**
* Tests that default policy settings are set correctly.
*/
@Test
public final void checkDefaultSettings() {
PolicySettings policy = new PolicySettings("Default Supply Chain Policy");
assertFalse(policy.isEcValidationEnabled());
assertFalse(policy.isPcValidationEnabled());
assertFalse(policy.isPcAttributeValidationEnabled());
assertFalse(policy.isExpiredCertificateValidationEnabled());
assertFalse(policy.isReplaceEC());
}
/**
* Tests that all setters and getters work.
*/
@Test
public final void flipDefaultSettings() {
PolicySettings policy = new PolicySettings("Default Supply Chain Policy");
policy.setEcValidationEnabled(false);
policy.setPcValidationEnabled(false);
policy.setPcAttributeValidationEnabled(false);
policy.setExpiredCertificateValidationEnabled(false);
policy.setReplaceEC(true);
assertFalse(policy.isEcValidationEnabled());
assertFalse(policy.isPcValidationEnabled());
assertFalse(policy.isPcAttributeValidationEnabled());
assertFalse(policy.isExpiredCertificateValidationEnabled());
assertTrue(policy.isReplaceEC());
}
/**
* Tests that we can initiate a policy with a description.
*/
@Test
public final void createPolicyWithDescription() {
final String description = "A default policy";
PolicySettings policy = new PolicySettings("Default Supply Chain Policy",
description);
assertEquals(description, policy.getDescription());
}
}

View File

@ -0,0 +1,221 @@
package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.enums.HealthStatus;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* Tests the functionality in SupplyChainValidationSummary.
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SupplyChainValidationSummaryTest extends AbstractUserdefinedEntityTest {
/**
* Test device.
*
*/
private Device device;
/**
* List of test certificates.
*
*/
private List<ArchivableEntity> certificates;
/**
* Create a set of certificates and a device for use by these tests.
*
* @throws Exception if there is a problem deserializing certificates or creating test device
*/
@BeforeAll
public void setup() throws Exception {
certificates = getAllTestCertificates();
device = getTestDevice("TestDevice");
}
/**
* Tests that an empty summary behaves as expected.
*/
@Test
public void testEmptySummary() throws InterruptedException {
SupplyChainValidationSummary emptySummary = getTestSummary(
0,
0
);
//assertEquals(device, emptySummary.getDevice());
assertEquals(device.getDeviceInfo(), emptySummary.getDevice().getDeviceInfo());
assertEquals(Collections.EMPTY_SET, emptySummary.getValidations());
assertEquals(AppraisalStatus.Status.PASS, emptySummary.getOverallValidationResult());
assertNotNull(emptySummary.getCreateTime());
}
/**
* Test that a summary can't be created with a null validationIdentifier.
*/
@Test
public void testNullValidationIdentifier() {
assertThrows(IllegalArgumentException.class, () ->
new SupplyChainValidationSummary(null, Collections.emptyList()));
}
/**
* Test that a summary can't be created with a null validations list.
*/
@Test
public void testNullValidationList() {
assertThrows(IllegalArgumentException.class, () ->
new SupplyChainValidationSummary(device, null));
}
/**
* Test that summaries with one and two component validations, which both represent successful
* validations, have getters that return the expected information.
*/
@Test
public void testSuccessfulSummary() throws InterruptedException {
SupplyChainValidationSummary oneValidation = getTestSummary(
1,
0
);
//assertEquals(device, oneValidation.getDevice());
assertEquals(device.getDeviceInfo(), oneValidation.getDevice().getDeviceInfo());
assertEquals(1, oneValidation.getValidations().size());
assertEquals(AppraisalStatus.Status.PASS, oneValidation.getOverallValidationResult());
assertNotNull(oneValidation.getCreateTime());
SupplyChainValidationSummary twoValidations = getTestSummary(
2,
0
);
//assertEquals(device, twoValidations.getDevice());
assertEquals(device.getDeviceInfo(), twoValidations.getDevice().getDeviceInfo());
assertEquals(2, twoValidations.getValidations().size());
assertEquals(twoValidations.getOverallValidationResult(), AppraisalStatus.Status.PASS);
assertNotNull(twoValidations.getCreateTime());
}
/**
* Test that summaries with one and two component validations, of which one represents an
* unsuccessful validations, have getters that return the expected information.
*/
@Test
public void testUnsuccessfulSummary() throws InterruptedException {
SupplyChainValidationSummary oneValidation = getTestSummary(
1,
1
);
//assertEquals(device, oneValidation.getDevice());
assertEquals(device.getDeviceInfo(), oneValidation.getDevice().getDeviceInfo());
assertEquals(1, oneValidation.getValidations().size());
assertEquals(AppraisalStatus.Status.FAIL, oneValidation.getOverallValidationResult());
assertNotNull(oneValidation.getCreateTime());
SupplyChainValidationSummary twoValidations = getTestSummary(
2,
1
);
//assertEquals(device, twoValidations.getDevice());
assertEquals(device.getDeviceInfo(), twoValidations.getDevice().getDeviceInfo());
assertEquals(2, twoValidations.getValidations().size());
assertEquals(AppraisalStatus.Status.FAIL, twoValidations.getOverallValidationResult());
assertNotNull(twoValidations.getCreateTime());
SupplyChainValidationSummary twoBadValidations = getTestSummary(
2,
2
);
//assertEquals(device, twoBadValidations.getDevice());
assertEquals(device.getDeviceInfo(), twoBadValidations.getDevice().getDeviceInfo());
assertEquals(2, twoBadValidations.getValidations().size());
assertEquals(AppraisalStatus.Status.FAIL, twoBadValidations.getOverallValidationResult());
assertNotNull(twoBadValidations.getCreateTime());
}
/**
* Utility method for getting a <code>Device</code> that can be used for
* testing.
*
* @param name name for the <code>Device</code>
*
* @return device
*/
public static Device getTestDevice(final String name) {
final DeviceInfoReport deviceInfo = getTestDeviceInfoReport();
return new Device(name, deviceInfo, HealthStatus.UNKNOWN,
AppraisalStatus.Status.UNKNOWN, null,
false, null, null);
}
/**
* Utility method for getting a <code>SupplyChainValidationSummary</code> that can be used for
* testing.
*
* @param numberOfValidations number of validations for the <code>SupplyChainValidationSummary</code>
* @param numFail number of failed validations
*
* @return device
*/
private SupplyChainValidationSummary getTestSummary(
final int numberOfValidations,
final int numFail
) throws InterruptedException {
SupplyChainValidation.ValidationType[] validationTypes =
SupplyChainValidation.ValidationType.values();
if (numberOfValidations > validationTypes.length) {
throw new IllegalArgumentException(String.format(
"Cannot have more than %d validation types",
validationTypes.length
));
}
if (numFail > numberOfValidations) {
throw new IllegalArgumentException(String.format(
"Cannot have more than %d failed validations",
validationTypes.length
));
}
Collection<SupplyChainValidation> validations = new HashSet<>();
for (int i = 0; i < numberOfValidations; i++) {
boolean successful = true;
if (i >= (numberOfValidations - numFail)) {
successful = false;
}
AppraisalStatus.Status result = AppraisalStatus.Status.FAIL;
if (successful) {
result = AppraisalStatus.Status.PASS;
}
validations.add(SupplyChainValidationTest.getTestSupplyChainValidation(
validationTypes[i],
result,
certificates
));
}
return new SupplyChainValidationSummary(device, validations);
}
}

View File

@ -1,21 +1,18 @@
package hirs.attestationca.persist.entity.userdefined; package hirs.attestationca.persist.entity.userdefined;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.enums.AppraisalStatus; import hirs.attestationca.persist.enums.AppraisalStatus;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/** /**
* Simple tests for the {@link SupplyChainValidation} class. Tests for the persistence of this * Simple tests for the {@link SupplyChainValidation} class. Tests for the persistence of this
* class are located in { SupplyChainValidationSummaryTest}. * class are located in { SupplyChainValidationSummaryTest}.
*/ */
class SupplyChainValidationTest { class SupplyChainValidationTest extends AbstractUserdefinedEntityTest {
private static final String MESSAGE = "Some message.";
/** /**
* Test that this class' getter methods work properly. * Test that this class' getter methods work properly.
@ -31,9 +28,9 @@ class SupplyChainValidationTest {
); );
assertEquals( assertEquals(
validation.getCertificatesUsed(), validation.getCertificatesUsed(),
CertificateTest.getAllTestCertificates() getAllTestCertificates()
); );
assertEquals(validation.getMessage(), MESSAGE); assertEquals(validation.getMessage(), VALIDATION_MESSAGE);
} }
/** /**
@ -47,8 +44,8 @@ class SupplyChainValidationTest {
new SupplyChainValidation( new SupplyChainValidation(
null, null,
AppraisalStatus.Status.PASS, AppraisalStatus.Status.PASS,
CertificateTest.getAllTestCertificates(), getAllTestCertificates(),
MESSAGE VALIDATION_MESSAGE
)); ));
} }
@ -64,7 +61,7 @@ class SupplyChainValidationTest {
SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL, SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL,
AppraisalStatus.Status.PASS, AppraisalStatus.Status.PASS,
null, null,
MESSAGE VALIDATION_MESSAGE
)); ));
} }
@ -78,8 +75,8 @@ class SupplyChainValidationTest {
new SupplyChainValidation( new SupplyChainValidation(
SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL, SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL,
AppraisalStatus.Status.PASS, AppraisalStatus.Status.PASS,
CertificateTest.getAllTestCertificates(), getAllTestCertificates(),
MESSAGE VALIDATION_MESSAGE
); );
} }
@ -95,27 +92,7 @@ class SupplyChainValidationTest {
return getTestSupplyChainValidation( return getTestSupplyChainValidation(
SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL, SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL,
AppraisalStatus.Status.PASS, AppraisalStatus.Status.PASS,
CertificateTest.getAllTestCertificates() getAllTestCertificates()
);
}
/**
* Construct a SupplyChainValidation for use in tests according to the provided parameters.
*
* @param type the type of validation
* @param result the appraisal result
* @param certificates the certificates related to this validation
* @return the resulting SupplyChainValidation object
*/
public static SupplyChainValidation getTestSupplyChainValidation(
final SupplyChainValidation.ValidationType type,
final AppraisalStatus.Status result,
final List<ArchivableEntity> certificates) {
return new SupplyChainValidation(
type,
result,
certificates,
MESSAGE
); );
} }
} }

View File

@ -1,8 +1,7 @@
package hirs.attestationca.persist.entity.userdefined.certificate; package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.userdefined.CertificateTest; import hirs.attestationca.persist.entity.userdefined.AbstractUserdefinedEntityTest;
import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.binary.Hex;
import static org.mockito.Mockito.mock;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -12,13 +11,11 @@ import java.net.URISyntaxException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
/** /**
* Tests that CertificateAuthorityCredential properly parses its fields. * Tests that CertificateAuthorityCredential properly parses its fields.
*/ */
public class CertificateAuthorityCredentialTest { public class CertificateAuthorityCredentialTest extends AbstractUserdefinedEntityTest {
private static final CertificateRepository CERT_MAN = mock(CertificateRepository.class);
/** /**
* Tests that a CertificateAuthorityCredential can be created from an X.509 certificate and * Tests that a CertificateAuthorityCredential can be created from an X.509 certificate and
@ -33,7 +30,7 @@ public class CertificateAuthorityCredentialTest {
public void testGetSubjectKeyIdentifier() public void testGetSubjectKeyIdentifier()
throws CertificateException, IOException, URISyntaxException { throws CertificateException, IOException, URISyntaxException {
Path testCertPath = Paths.get( Path testCertPath = Paths.get(
this.getClass().getResource(CertificateTest.FAKE_ROOT_CA_FILE).toURI() this.getClass().getResource(FAKE_ROOT_CA_FILE).toURI()
); );
CertificateAuthorityCredential caCred = new CertificateAuthorityCredential(testCertPath); CertificateAuthorityCredential caCred = new CertificateAuthorityCredential(testCertPath);
@ -42,7 +39,7 @@ public class CertificateAuthorityCredentialTest {
assertNotNull(subjectKeyIdentifier); assertNotNull(subjectKeyIdentifier);
assertEquals( assertEquals(
Hex.encodeHexString(subjectKeyIdentifier), Hex.encodeHexString(subjectKeyIdentifier),
CertificateTest.FAKE_ROOT_CA_SUBJECT_KEY_IDENTIFIER_HEX FAKE_ROOT_CA_SUBJECT_KEY_IDENTIFIER_HEX
); );
} }
} }

View File

@ -5,7 +5,6 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import hirs.attestationca.persist.entity.userdefined.CertificateTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.IOException; import java.io.IOException;
@ -29,13 +28,15 @@ public class EndorsementCredentialTest {
private static final String EK_CERT_WITH_SECURITY_ASSERTIONS = private static final String EK_CERT_WITH_SECURITY_ASSERTIONS =
"/certificates/ek_cert_with_security_assertions.cer"; "/certificates/ek_cert_with_security_assertions.cer";
private static final int TPM_SPEC_REVISION_NUM = 116;
/** /**
* Tests the successful parsing of an EC using a test cert from STM. * Tests the successful parsing of an EC using a test cert from STM.
* @throws IOException test failed due to invalid certificate parsing * @throws IOException test failed due to invalid certificate parsing
*/ */
@Test @Test
public void testParse() throws IOException { public void testParse() throws IOException {
String path = CertificateTest.class.getResource(TEST_ENDORSEMENT_CREDENTIAL). String path = this.getClass().getResource(TEST_ENDORSEMENT_CREDENTIAL).
getPath(); getPath();
Path fPath = Paths.get(path); Path fPath = Paths.get(path);
EndorsementCredential ec = new EndorsementCredential(fPath); EndorsementCredential ec = new EndorsementCredential(fPath);
@ -49,7 +50,7 @@ public class EndorsementCredentialTest {
TPMSpecification spec = ec.getTpmSpecification(); TPMSpecification spec = ec.getTpmSpecification();
assertEquals(spec.getFamily(), "1.2"); assertEquals(spec.getFamily(), "1.2");
assertEquals(spec.getLevel(), BigInteger.valueOf(2)); assertEquals(spec.getLevel(), BigInteger.valueOf(2));
assertEquals(spec.getRevision(), BigInteger.valueOf(116)); assertEquals(spec.getRevision(), BigInteger.valueOf(TPM_SPEC_REVISION_NUM));
TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions(); TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions();
assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0)); assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0));
@ -68,7 +69,7 @@ public class EndorsementCredentialTest {
*/ */
@Test @Test
public void testParseNuc1() throws IOException { public void testParseNuc1() throws IOException {
String path = CertificateTest.class.getResource( String path = this.getClass().getResource(
TEST_ENDORSEMENT_CREDENTIAL_NUC1).getPath(); TEST_ENDORSEMENT_CREDENTIAL_NUC1).getPath();
Path fPath = Paths.get(path); Path fPath = Paths.get(path);
EndorsementCredential ec = new EndorsementCredential(fPath); EndorsementCredential ec = new EndorsementCredential(fPath);
@ -82,7 +83,7 @@ public class EndorsementCredentialTest {
TPMSpecification spec = ec.getTpmSpecification(); TPMSpecification spec = ec.getTpmSpecification();
assertEquals(spec.getFamily(), "1.2"); assertEquals(spec.getFamily(), "1.2");
assertEquals(spec.getLevel(), BigInteger.valueOf(2)); assertEquals(spec.getLevel(), BigInteger.valueOf(2));
assertEquals(spec.getRevision(), BigInteger.valueOf(116)); assertEquals(spec.getRevision(), BigInteger.valueOf(TPM_SPEC_REVISION_NUM));
TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions(); TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions();
assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0)); assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0));
@ -102,7 +103,7 @@ public class EndorsementCredentialTest {
*/ */
@Test @Test
public void testParseNuc1BuilderMethod() throws IOException { public void testParseNuc1BuilderMethod() throws IOException {
String path = CertificateTest.class.getResource( String path = this.getClass().getResource(
TEST_ENDORSEMENT_CREDENTIAL_NUC1).getPath(); TEST_ENDORSEMENT_CREDENTIAL_NUC1).getPath();
Path fPath = Paths.get(path); Path fPath = Paths.get(path);
byte[] ecBytes = Files.readAllBytes(fPath); byte[] ecBytes = Files.readAllBytes(fPath);
@ -118,7 +119,7 @@ public class EndorsementCredentialTest {
TPMSpecification spec = ec.getTpmSpecification(); TPMSpecification spec = ec.getTpmSpecification();
assertEquals(spec.getFamily(), "1.2"); assertEquals(spec.getFamily(), "1.2");
assertEquals(spec.getLevel(), BigInteger.valueOf(2)); assertEquals(spec.getLevel(), BigInteger.valueOf(2));
assertEquals(spec.getRevision(), BigInteger.valueOf(116)); assertEquals(spec.getRevision(), BigInteger.valueOf(TPM_SPEC_REVISION_NUM));
TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions(); TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions();
assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0)); assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0));
@ -137,7 +138,7 @@ public class EndorsementCredentialTest {
*/ */
@Test @Test
public void testParseNuc2() throws IOException { public void testParseNuc2() throws IOException {
String path = CertificateTest.class.getResource( String path = this.getClass().getResource(
TEST_ENDORSEMENT_CREDENTIAL_NUC2).getPath(); TEST_ENDORSEMENT_CREDENTIAL_NUC2).getPath();
Path fPath = Paths.get(path); Path fPath = Paths.get(path);
EndorsementCredential ec = new EndorsementCredential(fPath); EndorsementCredential ec = new EndorsementCredential(fPath);
@ -151,7 +152,7 @@ public class EndorsementCredentialTest {
TPMSpecification spec = ec.getTpmSpecification(); TPMSpecification spec = ec.getTpmSpecification();
assertEquals(spec.getFamily(), "1.2"); assertEquals(spec.getFamily(), "1.2");
assertEquals(spec.getLevel(), BigInteger.valueOf(2)); assertEquals(spec.getLevel(), BigInteger.valueOf(2));
assertEquals(spec.getRevision(), BigInteger.valueOf(116)); assertEquals(spec.getRevision(), BigInteger.valueOf(TPM_SPEC_REVISION_NUM));
TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions(); TPMSecurityAssertions asserts = ec.getTpmSecurityAssertions();
assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0)); assertEquals(asserts.getTpmSecAssertsVersion(), BigInteger.valueOf(0));
@ -170,17 +171,17 @@ public class EndorsementCredentialTest {
*/ */
@Test @Test
public void testCertsNotEqual() throws IOException { public void testCertsNotEqual() throws IOException {
String path = CertificateTest.class.getResource(TEST_ENDORSEMENT_CREDENTIAL).getPath(); String path = this.getClass().getResource(TEST_ENDORSEMENT_CREDENTIAL).getPath();
Path fPath = Paths.get(path); Path fPath = Paths.get(path);
EndorsementCredential ec1 = new EndorsementCredential(fPath); EndorsementCredential ec1 = new EndorsementCredential(fPath);
assertNotNull(ec1); assertNotNull(ec1);
path = CertificateTest.class.getResource(TEST_ENDORSEMENT_CREDENTIAL_NUC1).getPath(); path = this.getClass().getResource(TEST_ENDORSEMENT_CREDENTIAL_NUC1).getPath();
fPath = Paths.get(path); fPath = Paths.get(path);
EndorsementCredential ec2 = new EndorsementCredential(fPath); EndorsementCredential ec2 = new EndorsementCredential(fPath);
assertNotNull(ec2); assertNotNull(ec2);
path = CertificateTest.class.getResource(TEST_ENDORSEMENT_CREDENTIAL_NUC2).getPath(); path = this.getClass().getResource(TEST_ENDORSEMENT_CREDENTIAL_NUC2).getPath();
fPath = Paths.get(path); fPath = Paths.get(path);
EndorsementCredential ec3 = new EndorsementCredential(fPath); EndorsementCredential ec3 = new EndorsementCredential(fPath);
assertNotNull(ec3); assertNotNull(ec3);
@ -197,7 +198,7 @@ public class EndorsementCredentialTest {
*/ */
@Test @Test
public void testTpmSecurityAssertionsParsing() throws IOException { public void testTpmSecurityAssertionsParsing() throws IOException {
Path fPath = Paths.get(CertificateTest.class Path fPath = Paths.get(this.getClass()
.getResource(EK_CERT_WITH_SECURITY_ASSERTIONS).getPath()); .getResource(EK_CERT_WITH_SECURITY_ASSERTIONS).getPath());
EndorsementCredential ec = new EndorsementCredential(fPath); EndorsementCredential ec = new EndorsementCredential(fPath);

View File

@ -1,5 +1,6 @@
package hirs.attestationca.persist.entity.userdefined.certificate; package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.userdefined.AbstractUserdefinedEntityTest;
import hirs.attestationca.persist.entity.userdefined.Certificate; import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
@ -25,42 +26,7 @@ import java.util.TimeZone;
/** /**
* Tests that a PlatformCredential parses its fields correctly. * Tests that a PlatformCredential parses its fields correctly.
*/ */
public class PlatformCredentialTest { public class PlatformCredentialTest extends AbstractUserdefinedEntityTest {
/**
* Location of a test platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_1 =
"/validation/platform_credentials/Intel_pc1.cer";
/**
* Location of another, slightly different platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_2 =
"/validation/platform_credentials/Intel_pc2.cer";
/**
* Location of another, slightly different platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_3 =
"/validation/platform_credentials/Intel_pc3.cer";
/**
* Platform cert with comma separated baseboard and chassis serial number.
*/
public static final String TEST_PLATFORM_CERT_4 =
"/validation/platform_credentials/Intel_pc4.pem";
/**
* Another platform cert with comma separated baseboard and chassis serial number.
*/
public static final String TEST_PLATFORM_CERT_5 =
"/validation/platform_credentials/Intel_pc5.pem";
/**
* Location of another, slightly different platform attribute cert.
*/
public static final String TEST_PLATFORM_CERT_6 =
"/validation/platform_credentials/TPM_INTC_Platform_Cert_RSA.txt";
/** /**
* Platform Certificate 2.0 with all the expected data. * Platform Certificate 2.0 with all the expected data.
@ -573,7 +539,7 @@ public class PlatformCredentialTest {
.equals("BIOS")); .equals("BIOS"));
Assertions.assertTrue(component.getComponentSerial() Assertions.assertTrue(component.getComponentSerial()
.getString() .getString()
.equals(ComponentIdentifier.EMPTY_COMPONENT)); .equals(ComponentIdentifier.NOT_SPECIFIED_COMPONENT));
Assertions.assertTrue(component.getComponentRevision() Assertions.assertTrue(component.getComponentRevision()
.getString() .getString()
.equals("DNKBLi5v.86A.0019.2017.0804.1146")); .equals("DNKBLi5v.86A.0019.2017.0804.1146"));

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity.userdefined.certificate;

View File

@ -1,12 +1,8 @@
package hirs.attestationca.persist.entity.userdefined.info; package hirs.attestationca.persist.entity.userdefined.info;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED; import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import hirs.attestationca.persist.entity.userdefined.AbstractUserdefinedEntityTest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -18,12 +14,11 @@ import org.junit.jupiter.api.Test;
/** /**
* TPMInfoTest is a unit test class for TPMInfo. * TPMInfoTest is a unit test class for TPMInfo.
*/ */
public class TPMInfoTest { public class TPMInfoTest extends AbstractUserdefinedEntityTest {
private static final String TPM_MAKE = "test tpmMake"; private static final String TPM_MAKE = "test tpmMake";
private static final String LONG_TPM_MAKE = StringUtils.rightPad("test tpmMake", 65); private static final String LONG_TPM_MAKE = StringUtils.rightPad("test tpmMake", 65);
private static final String TEST_IDENTITY_CERT =
"/tpm/sample_identity_cert.cer";
private static final short VERSION_MAJOR = 1; private static final short VERSION_MAJOR = 1;
private static final short VERSION_MINOR = 2; private static final short VERSION_MINOR = 2;
private static final short VERSION_REV_MAJOR = 3; private static final short VERSION_REV_MAJOR = 3;
@ -327,30 +322,4 @@ public class TPMInfoTest {
getTestIdentityCertificate()); getTestIdentityCertificate());
assertNotEquals(ti1, ti2); assertNotEquals(ti1, ti2);
} }
private X509Certificate getTestIdentityCertificate() {
X509Certificate certificateValue = null;
InputStream istream = null;
istream = getClass().getResourceAsStream(TEST_IDENTITY_CERT);
try {
if (istream == null) {
throw new FileNotFoundException(TEST_IDENTITY_CERT);
}
CertificateFactory cf = CertificateFactory.getInstance("X.509");
certificateValue = (X509Certificate) cf.generateCertificate(
istream);
} catch (Exception e) {
return null;
} finally {
if (istream != null) {
try {
istream.close();
} catch (IOException e) {
LOGGER.error("test certificate file could not be closed");
}
}
}
return certificateValue;
}
} }

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity.userdefined.info;

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity.userdefined;

View File

@ -26,7 +26,8 @@ public class TPMMeasurementRecordTest {
private static final int DEFAULT_PCR_ID = 3; private static final int DEFAULT_PCR_ID = 3;
private static final String DEFAULT_HASH = private static final String DEFAULT_HASH =
"3d5f3c2f7f3003d2e4baddc46ed4763a4954f648"; "3d5f3c2f7f3003d2e4baddc46ed4763a4954f648";
private static final ExaminableRecord.ExamineState DEFAULT_STATE = ExaminableRecord.ExamineState.UNEXAMINED; private static final ExaminableRecord.ExamineState DEFAULT_STATE =
ExaminableRecord.ExamineState.UNEXAMINED;
/** /**
* Tests instantiation of new <code>PCRMeasurementRecord</code>. * Tests instantiation of new <code>PCRMeasurementRecord</code>.

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity.userdefined.record;

View File

@ -1,37 +1,25 @@
package hirs.attestationca.persist.entity.userdefined.report; package hirs.attestationca.persist.entity.userdefined.report;
import hirs.attestationca.persist.entity.userdefined.AbstractUserdefinedEntityTest;
import hirs.attestationca.persist.entity.userdefined.info.OSInfo; import hirs.attestationca.persist.entity.userdefined.info.OSInfo;
import hirs.attestationca.persist.entity.userdefined.info.TPMInfo; import hirs.attestationca.persist.entity.userdefined.info.TPMInfo;
import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo; import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo;
import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo; import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo;
import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo; import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/** /**
* DeviceInfoReportTest is a unit test class for DeviceInfoReports. * Unit test class for DeviceInfoReports.
*/ */
public class DeviceInfoReportTest { public class DeviceInfoReportTest extends AbstractUserdefinedEntityTest {
private final NetworkInfo networkInfo = createTestNetworkInfo(); private final NetworkInfo networkInfo = createTestNetworkInfo();
private final OSInfo osInfo = createTestOSInfo(); private final OSInfo osInfo = createTestOSInfo();
private final FirmwareInfo firmwareInfo = createTestFirmwareInfo(); private final FirmwareInfo firmwareInfo = createTestFirmwareInfo();
private final HardwareInfo hardwareInfo = createTestHardwareInfo(); private final HardwareInfo hardwareInfo = createTestHardwareInfo();
private final TPMInfo tpmInfo = createTPMInfo(); private final TPMInfo tpmInfo = createTPMInfo();
private static final String TEST_IDENTITY_CERT = "/tpm/sample_identity_cert.cer";
private static final Logger LOGGER = LogManager.getLogger(DeviceInfoReportTest.class);
private static final String EXPECTED_CLIENT_VERSION = "Test.Version"; private static final String EXPECTED_CLIENT_VERSION = "Test.Version";
@ -101,109 +89,4 @@ public class DeviceInfoReportTest {
assertEquals(tpmInfo, deviceInfoReport.getTpmInfo()); assertEquals(tpmInfo, deviceInfoReport.getTpmInfo());
assertEquals(EXPECTED_CLIENT_VERSION, deviceInfoReport.getClientApplicationVersion()); assertEquals(EXPECTED_CLIENT_VERSION, deviceInfoReport.getClientApplicationVersion());
} }
/**
* Creates a DeviceInfoReport instance usable for testing.
*
* @return a test DeviceInfoReport
*/
public static DeviceInfoReport getTestReport() {
return new DeviceInfoReport(
createTestNetworkInfo(), createTestOSInfo(), createTestFirmwareInfo(),
createTestHardwareInfo(), createTPMInfo()
);
}
/**
* Creates a test instance of NetworkInfo.
*
* @return network information for a fake device
*/
public static NetworkInfo createTestNetworkInfo() {
try {
final String hostname = "test.hostname";
final InetAddress ipAddress =
InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
final byte[] macAddress = new byte[] {11, 22, 33, 44, 55, 66};
return new NetworkInfo(hostname, ipAddress, macAddress);
} catch (UnknownHostException e) {
LOGGER.error("error occurred while creating InetAddress");
return null;
}
}
/**
* Creates a test instance of OSInfo.
*
* @return OS information for a fake device
*/
public static OSInfo createTestOSInfo() {
return new OSInfo("test os name", "test os version", "test os arch",
"test distribution", "test distribution release");
}
/**
* Creates a test instance of FirmwareInfo.
*
* @return Firmware information for a fake device
*/
public static FirmwareInfo createTestFirmwareInfo() {
return new FirmwareInfo("test bios vendor", "test bios version", "test bios release date");
}
/**
* Creates a test instance of HardwareInfo.
*
* @return Hardware information for a fake device
*/
public static HardwareInfo createTestHardwareInfo() {
return new HardwareInfo("test manufacturer", "test product name", "test version",
"test really long serial number with many characters", "test really long chassis "
+ "serial number with many characters",
"test really long baseboard serial number with many characters");
}
/**
* Creates a test instance of TPMInfo.
*
* @return TPM information for a fake device
*/
public static final TPMInfo createTPMInfo() {
final short num1 = 1;
final short num2 = 2;
final short num3 = 3;
final short num4 = 4;
return new TPMInfo("test os make", num1, num2, num3, num4,
getTestIdentityCertificate());
}
private static X509Certificate getTestIdentityCertificate() {
X509Certificate certificateValue = null;
InputStream istream = null;
istream = DeviceInfoReportTest.class.getResourceAsStream(
TEST_IDENTITY_CERT
);
try {
if (istream == null) {
throw new FileNotFoundException(TEST_IDENTITY_CERT);
}
CertificateFactory cf = CertificateFactory.getInstance("X.509");
certificateValue = (X509Certificate) cf.generateCertificate(
istream);
} catch (Exception e) {
return null;
} finally {
if (istream != null) {
try {
istream.close();
} catch (IOException e) {
LOGGER.error("test certificate file could not be closed");
}
}
}
return certificateValue;
}
} }

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.entity.userdefined.report;

View File

@ -0,0 +1 @@
package hirs.attestationca.persist;

View File

@ -65,7 +65,8 @@ public class CredentialManagementHelperTest {
@Test @Test
public void processEmptyEndorsementCredential() { public void processEmptyEndorsementCredential() {
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
CredentialManagementHelper.storeEndorsementCredential(certificateRepository, new byte[0], "testName")); CredentialManagementHelper.storeEndorsementCredential(
certificateRepository, new byte[0], "testName"));
} }
/** /**
@ -75,7 +76,8 @@ public class CredentialManagementHelperTest {
public void processInvalidEndorsementCredentialCase1() { public void processInvalidEndorsementCredentialCase1() {
byte[] ekBytes = new byte[] {1}; byte[] ekBytes = new byte[] {1};
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
CredentialManagementHelper.storeEndorsementCredential(certificateRepository, ekBytes, "testName")); CredentialManagementHelper.storeEndorsementCredential(
certificateRepository, ekBytes, "testName"));
} }
/** /**

View File

@ -186,7 +186,7 @@ public class IssuedCertificateAttributeHelperTest {
} }
private Map<String, String> getSubjectAlternativeNameAttributes( private Map<String, String> getSubjectAlternativeNameAttributes(
Extension subjectAlternativeName) { final Extension subjectAlternativeName) {
Map<String, String> subjectAlternativeNameAttrMap = new HashMap<>(); Map<String, String> subjectAlternativeNameAttrMap = new HashMap<>();
DLSequence dlSequence = (DLSequence) subjectAlternativeName.getParsedValue(); DLSequence dlSequence = (DLSequence) subjectAlternativeName.getParsedValue();

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.provision.helper;

View File

@ -0,0 +1 @@
package hirs.attestationca.persist.validation;

View File

@ -0,0 +1,36 @@
{
"PLATFORM": {
"PLATFORMMANUFACTURERSTR": "innotek GmbH","PLATFORMMODEL": "VirtualBox","PLATFORMVERSION": "1.2","PLATFORMSERIAL": "0"
},
"COMPONENTS": [
{
"COMPONENTCLASS": {
"COMPONENTCLASSREGISTRY": "2.23.133.18.3.1",
"COMPONENTCLASSVALUE": "00010002"
},"MANUFACTURER": "Intel","MODEL": "Core i7","SERIAL": "Not Specified","REVISION": "Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz"
},
{
"COMPONENTCLASS": {
"COMPONENTCLASSREGISTRY": "2.23.133.18.3.1",
"COMPONENTCLASSVALUE": "00050004"
},"MANUFACTURER": "Intel Corporation","MODEL": "Ethernet Connection I217-V", "FIELDREPLACEABLE": "false","SERIAL": "23:94:17:ba:86:5e", "REVISION": "00"
},
{
"COMPONENTCLASS": {
"COMPONENTCLASSREGISTRY": "2.23.133.18.3.1",
"COMPONENTCLASSVALUE": "00090002"
},"MANUFACTURER": "Intel Corporation","MODEL": "82580 Gigabit Network Connection", "FIELDREPLACEABLE": "false", "SERIAL": "90:e2:ba:31:83:10", "REVISION": ""
}
],
"PROPERTIES": [
{
"NAME": "uname -r",
"VALUE": "3.10.0-862.11.6.el7.x86_64"
},
{
"NAME": "cat /etc/centos-release",
"VALUE": "CentOS Linux release 7.5.1804 (Core) "
}
]
}

View File

@ -0,0 +1,34 @@
{
"PLATFORM": {
"PLATFORMMANUFACTURERSTR": "Not Specified","PLATFORMMODEL": "Not Specified","PLATFORMVERSION": "Not Specified"
},
"COMPONENTS": [
{
"MANUFACTURER": "Not Specified","MODEL": "Not Specified"
},
{
"MANUFACTURER": "Not Specified","MODEL": "Not Specified","FIELDREPLACEABLE": "false"
},
{
"MANUFACTURER": "Not Specified","MODEL": "UEFI"
},
{
"MANUFACTURER": "Broadcom Inc. and subsidiaries","MODEL": "NetXtreme BCM5722 Gigabit Ethernet PCI Express","FIELDREPLACEABLE": "true","REVISION": "00"
},
{
"MANUFACTURER": "Intel Corporation","MANUFACTURERID": "1.3.6.1.4.1.343","MODEL": "Ethernet Connection (2) I219-LM","FIELDREPLACEABLE": "true","REVISION": "31"
}
],
"PROPERTIES": [
{
"NAME": "uname -r",
"VALUE": "3.10.0-957.1.3.el7.x86_64"
},
{
"NAME": "OS Release",
"VALUE": "CentOS Linux 7 (Core)"
}
]
}

View File

@ -0,0 +1,30 @@
{
"PLATFORM": {
"PLATFORMMANUFACTURERSTR": "innotek GmbH","PLATFORMMODEL": "VirtualBox","PLATFORMVERSION": "1.2","PLATFORMSERIAL": "0"
},
"COMPONENTS": [
{
"MANUFACTURER": "Intel","MODEL": "Core i7","SERIAL": "Not Specified","REVISION": "Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz"
},
{
"MANUFACTURER": "Intel Corporation","MODEL": "Ethernet Connection I217-V", "FIELDREPLACEABLE": "false","SERIAL": "23:94:17:ba:86:5e", "REVISION": "00"
},
{
"MANUFACTURER": "Intel Corporation","MODEL": "82580 Gigabit Network Connection", "FIELDREPLACEABLE": "false", "SERIAL": "90:e2:ba:31:83:10", "REVISION": ""
},
{
"MANUFACTURER": "Intel","MODEL": "platform2018", "FIELDREPLACEABLE": "false", "SERIAL": "BQKP52840678", "REVISION": "1.0"
}
],
"PROPERTIES": [
{
"NAME": "uname -r",
"VALUE": "3.10.0-862.11.6.el7.x86_64"
},
{
"NAME": "cat /etc/centos-release",
"VALUE": "CentOS Linux release 7.5.1804 (Core) "
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,37 @@
-----BEGIN ATTRIBUTE CERTIFICATE-----
MIIHuzCCBqMCAQEwc6BxMFmkVzBVMQswCQYDVQQGEwJDSDEeMBwGA1UEChMVU1RNaWNyb2VsZWN0
cm9uaWNzIE5WMSYwJAYDVQQDEx1TVE0gVFBNIEVLIEludGVybWVkaWF0ZSBDQSAwMgIUS5gujeW5
kYvYdMJZlIUT6s3F0cygOjA4pDYwNDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2V4YW1wbGUuY29t
MQ8wDQYDVQQLDAZQQ1Rlc3QwDQYJKoZIhvcNAQELBQACAQEwIhgPMjAxODAxMDEwNTAwMDBaGA8y
MDI4MDEwMTA1MDAwMFowggRkMAsGBWeBBQITMQIwADAcBgVngQUCETETMBEwCQIBAQIBAwIBFgQE
AAAAATASBgVngQUCGTEJMAcGBWeBBQgCMIIECwYHZ4EFBQEHAjGCA/4wggP6oIID9DBbMA4GBmeB
BRIDAQQEAAIAAQwWVG8gQmUgRmlsbGVkIEJ5IE8uRS5NLgwBM4AWVG8gQmUgRmlsbGVkIEJ5IE8u
RS5NLoEWVG8gQmUgRmlsbGVkIEJ5IE8uRS5NLjAoMA4GBmeBBRIDAQQEAAMAAwwGQVNSb2NrDAtY
NTggRXh0cmVtZYMB/zBAMA4GBmeBBRIDAQQEABMAAwwYQW1lcmljYW4gTWVnYXRyZW5kcyBJbmMu
DA1Ob3QgU3BlY2lmaWVkgQVQMi45MDBoMA4GBmeBBRIDAQQEAAEAAgwFSW50ZWwMAzE5OIAWVG8g
QmUgRmlsbGVkIEJ5IE8uRS5NLoEvSW50ZWwoUikgQ29yZShUTSkgaTcgQ1BVICAgICAgICAgOTIw
ICBAIDIuNjdHSHqDAf8wSjAOBgZngQUSAwEEBAAGAAEMDk1hbnVmYWN0dXJlcjAwDA1PQ1ozRzE2
MDBMVjJHgAgwMDAwMDAwMIEMQXNzZXRUYWdOdW0wgwH/MEowDgYGZ4EFEgMBBAQABgABDA5NYW51
ZmFjdHVyZXIwMQwNT0NaM0cxNjAwTFYyR4AIMDAwMDAwMDCBDEFzc2V0VGFnTnVtMYMB/zBKMA4G
BmeBBRIDAQQEAAYAAQwOTWFudWZhY3R1cmVyMDIMDU5vdCBTcGVjaWZpZWSACDAwMDAwMDAwgQxB
c3NldFRhZ051bTKDAf8wSjAOBgZngQUSAwEEBAAGAAEMDk1hbnVmYWN0dXJlcjAzDA1PQ1ozRzE2
MDBMVjJHgAgwMDAwMDAwMIEMQXNzZXRUYWdOdW0zgwH/MEowDgYGZ4EFEgMBBAQABgABDA5NYW51
ZmFjdHVyZXIwNAwNT0NaM0cxNjAwTFYyR4AIMDAwMDAwMDCBDEFzc2V0VGFnTnVtNIMB/zBKMA4G
BmeBBRIDAQQEAAYAAQwOTWFudWZhY3R1cmVyMDUMDU5vdCBTcGVjaWZpZWSACDAwMDAwMDAwgQxB
c3NldFRhZ051bTWDAf8wSjAOBgZngQUSAwEEBAAJAAIMBDgwODYMBDI0RjOADEE0MzREOTEyMzQ1
NoECM0GDAf+kFzAVBgVngQURAgwMQTQzNEQ5MTIzNDU2MEowDgYGZ4EFEgMBBAQACQACDAQxMEVD
DAQ4MTY4gAwwMDE5NjZBQkNERUaBAjAzgwH/pBcwFQYFZ4EFEQEMDDAwMTk2NkFCQ0RFRjA6MA4G
BmeBBRIDAQQEAAcAAgwNTm90IFNwZWNpZmllZAwMU1QzMTUwMDM0MUFTgAg4WDY4WTMyMIMB/zAj
MA4GBmeBBRIDAQQEAAUAAgwEMTAwMgwENjg5OYECMDCDAf+iADAUBgVngQUCFzELMAkCAQECAQEC
AREwggFNMGQGA1UdIwRdMFuAFGQP4SIG+UWEJp5BdqBD3dUDaRgOoTikNjA0MQswCQYDVQQGEwJV
UzEUMBIGA1UECgwLZXhhbXBsZS5jb20xDzANBgNVBAsMBlBDVGVzdIIJAISFLMl6DJA8MEEGA1Ud
IAQ6MDgwNgYCKgMwMDAuBggrBgEFBQcCAjAiDCBUQ0cgVHJ1c3RlZCBQbGF0Zm9ybSBFbmRvcnNl
bWVudDCBoQYDVR0RBIGZMIGWpIGTMIGQMSIwIAYGZ4EFBQEEDBZUbyBCZSBGaWxsZWQgQnkgTy5F
Lk0uMSIwIAYGZ4EFBQEBDBZUbyBCZSBGaWxsZWQgQnkgTy5FLk0uMSIwIAYGZ4EFBQEFDBZUbyBC
ZSBGaWxsZWQgQnkgTy5FLk0uMSIwIAYGZ4EFBQEGDBZUbyBCZSBGaWxsZWQgQnkgTy5FLk0uMA0G
CSqGSIb3DQEBCwUAA4IBAQCiJcOtpVn43jbGkEhNq0rfdtnvnn9/N99eNeYO2+jGbKOQDkC1TxYO
QXgaWl32KVc9q044KX4062tt2cQHIwFDK7dPLAaUkCJ8x7mjg7Np7ddzqWHtkAyr+USntdjf0o/z
8Ru5aUSVBA0sphpRN66nVU8sGKSf31CZhSBMpBCToKyil+eFUF3n6X2Z9fjhzermoPVNqkff7/Ai
cldsbnTb46CGdQSWhctw7sbyy9B9VTYbqDMfMQdpifl2JQBkXaC7XPe9Z6J8VJVWiTh91be5JSAd
Uyq5/X2IajIEGp8OP+zQSaStT2RaoeN1VdmPGrv87YbUs9buKTpTSYNZwI2d
-----END ATTRIBUTE CERTIFICATE-----

View File

@ -6,18 +6,20 @@ import hirs.attestationca.persist.DBServiceException;
import hirs.attestationca.persist.FilteredRecordsList; import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.CACredentialRepository; import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.EndorsementCredentialRepository; import hirs.attestationca.persist.entity.manager.EndorsementCredentialRepository;
import hirs.attestationca.persist.entity.manager.IssuedCertificateRepository; import hirs.attestationca.persist.entity.manager.IssuedCertificateRepository;
import hirs.attestationca.persist.entity.manager.PlatformCertificateRepository; import hirs.attestationca.persist.entity.manager.PlatformCertificateRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate; import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential; 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.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate; import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.util.CredentialHelper; import hirs.attestationca.persist.util.CredentialHelper;
import hirs.attestationca.portal.datatables.DataTableInput; import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse; import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page; import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController; import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages; import hirs.attestationca.portal.page.PageMessages;
@ -83,6 +85,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
private CertificateAuthorityCredential certificateAuthorityCredential; private CertificateAuthorityCredential certificateAuthorityCredential;
private final CertificateRepository certificateRepository; private final CertificateRepository certificateRepository;
private final PlatformCertificateRepository platformCertificateRepository; private final PlatformCertificateRepository platformCertificateRepository;
private final ComponentResultRepository componentResultRepository;
private final EndorsementCredentialRepository endorsementCredentialRepository; private final EndorsementCredentialRepository endorsementCredentialRepository;
private final IssuedCertificateRepository issuedCertificateRepository; private final IssuedCertificateRepository issuedCertificateRepository;
private final CACredentialRepository caCredentialRepository; private final CACredentialRepository caCredentialRepository;
@ -102,6 +105,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
* *
* @param certificateRepository the general certificate manager * @param certificateRepository the general certificate manager
* @param platformCertificateRepository the platform credential manager * @param platformCertificateRepository the platform credential manager
* @param componentResultRepository the component result repo
* @param endorsementCredentialRepository the endorsement credential manager * @param endorsementCredentialRepository the endorsement credential manager
* @param issuedCertificateRepository the issued certificate manager * @param issuedCertificateRepository the issued certificate manager
* @param caCredentialRepository the ca credential manager * @param caCredentialRepository the ca credential manager
@ -110,6 +114,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
@Autowired @Autowired
public CertificatePageController(final CertificateRepository certificateRepository, public CertificatePageController(final CertificateRepository certificateRepository,
final PlatformCertificateRepository platformCertificateRepository, final PlatformCertificateRepository platformCertificateRepository,
final ComponentResultRepository componentResultRepository,
final EndorsementCredentialRepository endorsementCredentialRepository, final EndorsementCredentialRepository endorsementCredentialRepository,
final IssuedCertificateRepository issuedCertificateRepository, final IssuedCertificateRepository issuedCertificateRepository,
final CACredentialRepository caCredentialRepository, final CACredentialRepository caCredentialRepository,
@ -117,6 +122,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
super(Page.TRUST_CHAIN); super(Page.TRUST_CHAIN);
this.certificateRepository = certificateRepository; this.certificateRepository = certificateRepository;
this.platformCertificateRepository = platformCertificateRepository; this.platformCertificateRepository = platformCertificateRepository;
this.componentResultRepository = componentResultRepository;
this.endorsementCredentialRepository = endorsementCredentialRepository; this.endorsementCredentialRepository = endorsementCredentialRepository;
this.issuedCertificateRepository = issuedCertificateRepository; this.issuedCertificateRepository = issuedCertificateRepository;
this.caCredentialRepository = caCredentialRepository; this.caCredentialRepository = caCredentialRepository;
@ -395,9 +401,11 @@ public class CertificatePageController extends PageController<NoPageParams> {
if (!pc.isPlatformBase()) { if (!pc.isPlatformBase()) {
pc.archive("User requested deletion via UI of the base certificate"); pc.archive("User requested deletion via UI of the base certificate");
certificateRepository.save(pc); certificateRepository.save(pc);
deleteComponentResults(pc.getPlatformSerial());
} }
} }
} }
deleteComponentResults(platformCertificate.getPlatformSerial());
} }
certificate.archive("User requested deletion via UI"); certificate.archive("User requested deletion via UI");
@ -845,7 +853,6 @@ public class CertificatePageController extends PageController<NoPageParams> {
* be stored * be stored
* @param messages contains any messages that will be display on the page * @param messages contains any messages that will be display on the page
* @param certificate the certificate to store * @param certificate the certificate to store
* @return the messages for the page
*/ */
private void storeCertificate( private void storeCertificate(
final String certificateType, final String certificateType,
@ -877,8 +884,6 @@ public class CertificatePageController extends PageController<NoPageParams> {
List<PlatformCredential> sharedCertificates = getCertificateByBoardSN( List<PlatformCredential> sharedCertificates = getCertificateByBoardSN(
certificateType, certificateType,
platformCertificate.getPlatformSerial()); platformCertificate.getPlatformSerial());
if (sharedCertificates != null) {
for (PlatformCredential pc : sharedCertificates) { for (PlatformCredential pc : sharedCertificates) {
if (pc.isPlatformBase()) { if (pc.isPlatformBase()) {
final String failMessage = "Storing certificate failed: " final String failMessage = "Storing certificate failed: "
@ -891,7 +896,6 @@ public class CertificatePageController extends PageController<NoPageParams> {
return; return;
} }
} }
}
} /**else { } /**else {
// this is a delta, check if the holder exists. // this is a delta, check if the holder exists.
PlatformCredential holderPC = PlatformCredential PlatformCredential holderPC = PlatformCredential
@ -913,6 +917,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
} }
this.certificateRepository.save(certificate); this.certificateRepository.save(certificate);
handlePlatformComponents(certificate);
final String successMsg final String successMsg
= String.format("New certificate successfully uploaded (%s): ", fileName); = String.format("New certificate successfully uploaded (%s): ", fileName);
@ -936,6 +941,15 @@ public class CertificatePageController extends PageController<NoPageParams> {
existingCertificate.resetCreateTime(); existingCertificate.resetCreateTime();
this.certificateRepository.save(existingCertificate); this.certificateRepository.save(existingCertificate);
List<ComponentResult> componentResults = componentResultRepository
.findByBoardSerialNumber(((PlatformCredential) existingCertificate)
.getPlatformSerial());
for (ComponentResult componentResult : componentResults) {
componentResult.restore();
componentResult.resetCreateTime();
this.componentResultRepository.save(componentResult);
}
final String successMsg = String.format("Pre-existing certificate " final String successMsg = String.format("Pre-existing certificate "
+ "found and unarchived (%s): ", fileName); + "found and unarchived (%s): ", fileName);
messages.addSuccess(successMsg); messages.addSuccess(successMsg);
@ -958,4 +972,34 @@ public class CertificatePageController extends PageController<NoPageParams> {
messages.addError(failMessage); messages.addError(failMessage);
log.error(failMessage); log.error(failMessage);
} }
private int handlePlatformComponents(final Certificate certificate) {
PlatformCredential platformCredential;
int componentResults = 0;
if (certificate instanceof PlatformCredential) {
platformCredential = (PlatformCredential) certificate;
ComponentResult componentResult;
for (ComponentIdentifier componentIdentifier : platformCredential
.getComponentIdentifiers()) {
componentResult = new ComponentResult(platformCredential.getPlatformSerial(),
platformCredential.getSerialNumber().toString(),
platformCredential.getPlatformChainType(),
componentIdentifier);
componentResultRepository.save(componentResult);
componentResults++;
}
}
return componentResults;
}
private void deleteComponentResults(final String platformSerial) {
List<ComponentResult> componentResults = componentResultRepository
.findByBoardSerialNumber(platformSerial);
for (ComponentResult componentResult : componentResults) {
componentResult.archive();
componentResultRepository.save(componentResult);
}
}
} }

View File

@ -11,8 +11,8 @@ import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestati
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
import hirs.utils.BouncyCastleUtils;
import hirs.attestationca.persist.util.PciIds; import hirs.attestationca.persist.util.PciIds;
import hirs.utils.BouncyCastleUtils;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
@ -25,7 +25,6 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -365,21 +364,13 @@ public final class CertificateStringMapBuilder {
data.put("x509Version", certificate.getX509CredentialVersion()); data.put("x509Version", certificate.getX509CredentialVersion());
//CPSuri //CPSuri
data.put("CPSuri", certificate.getCPSuri()); data.put("CPSuri", certificate.getCPSuri());
//Component Identifier - attempt to translate hardware IDs
if (!certificate.getComponentFailures().isEmpty()) { List<ComponentResult> compResults = componentResultRepository
data.put("failures", certificate.getComponentFailures()); .findByBoardSerialNumber(certificate.getPlatformSerial());
HashMap<Integer, String> results = new HashMap<>(); if (PciIds.DB.isReady()) {
for (ComponentResult componentResult : componentResultRepository.findAll()) { compResults = PciIds.translateResults(compResults);
if (componentResult.getCertificateId()
.equals(certificate.getId())) {
results.put(componentResult.getComponentHash(),
componentResult.getExpected());
}
}
data.put("componentResults", results);
data.put("failureMessages", certificate.getComponentFailures());
} }
data.put("componentResults", compResults);
//Get platform Configuration values and set map with it //Get platform Configuration values and set map with it
PlatformConfiguration platformConfiguration = certificate.getPlatformConfiguration(); PlatformConfiguration platformConfiguration = certificate.getPlatformConfiguration();

View File

@ -601,7 +601,7 @@
<div class="row"> <div class="row">
<div class="col-md-1 col-md-offset-1"><span class="colHeader">TCG Platform Configuration</span></div> <div class="col-md-1 col-md-offset-1"><span class="colHeader">TCG Platform Configuration</span></div>
<div id="platformConfiguration" class="col col-md-8"> <div id="platformConfiguration" class="col col-md-8">
<c:if test="${not empty initialData.componentsIdentifier}"> <c:if test="${not empty initialData.componentResults}">
<!-- Component Identifier --> <!-- Component Identifier -->
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne"> <div class="panel-heading" role="tab" id="headingOne">
@ -615,12 +615,11 @@
<div id="componentIdentifiercollapse" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne" aria-expanded="true"> <div id="componentIdentifiercollapse" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne" aria-expanded="true">
<div class="panel-body"> <div class="panel-body">
<div id="componentIdentifier" class="row"> <div id="componentIdentifier" class="row">
<c:forEach items="${initialData.componentsIdentifier}" var="component"> <c:forEach items="${initialData.componentResults}" var="component">
<c:set var="combined" value="${component.hashCode()}" scope="page"/>
<div class="component col col-md-4"> <div class="component col col-md-4">
<div class="panel panel-default"> <div class="panel panel-default">
<c:choose> <c:choose>
<c:when test="${fn:contains(initialData.failures, combined)}"> <c:when test="${component.isFailedValidation() =='TRUE'}">
<div class="panel-heading" style="background-color: red; color: white"> <div class="panel-heading" style="background-color: red; color: white">
</c:when> </c:when>
<c:otherwise> <c:otherwise>
@ -629,7 +628,7 @@
</c:choose> </c:choose>
<c:choose> <c:choose>
<c:when test="${component.isVersion2()=='TRUE'}"> <c:when test="${component.isVersion2()=='TRUE'}">
<span data-toggle="tooltip" data-placement="top" title="Component Class">${component.getComponentClass()}</span> <span data-toggle="tooltip" data-placement="top" title="Component Class">${component.getComponentClassStr()}</span>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<span data-toggle="tooltip" data-placement="top" title="Component Class">Platform Components</span> <span data-toggle="tooltip" data-placement="top" title="Component Class">Platform Components</span>
@ -638,23 +637,23 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<span class="fieldHeader">Manufacturer:</span> <span class="fieldHeader">Manufacturer:</span>
<span class="fieldValue">${component.getComponentManufacturer()}</span><br/> <span class="fieldValue">${component.getManufacturer()}</span><br/>
<span class="fieldHeader">Model:</span> <span class="fieldHeader">Model:</span>
<span class="fieldValue">${component.getComponentModel()}</span><br/> <span class="fieldValue">${component.getModel()}</span><br/>
<c:if test="${not empty fn:trim(component.getComponentSerial())}"> <c:if test="${not empty fn:trim(component.getSerialNumber())}">
<span class="fieldHeader">Serial Number:</span> <span class="fieldHeader">Serial Number:</span>
<span class="fieldValue">${component.getComponentSerial()}</span><br/> <span class="fieldValue">${component.getSerialNumber()}</span><br/>
</c:if> </c:if>
<c:if test="${not empty fn:trim(component.getComponentRevision())}"> <c:if test="${not empty fn:trim(component.getRevisionNumber())}">
<span class="fieldHeader">Revision:</span> <span class="fieldHeader">Revision:</span>
<span class="fieldValue">${component.getComponentRevision()}</span><br/> <span class="fieldValue">${component.getRevisionNumber()}</span><br/>
</c:if> </c:if>
<c:forEach items="${component.getComponentAddress()}" var="address"> <c:forEach items="${component.getComponentAddresses()}" var="address">
<span class="fieldHeader">${address.getAddressTypeValue()} address:</span> <span class="fieldHeader">${address.getAddressTypeString()} address:</span>
<span class="fieldValue">${address.getAddressValue()}</span><br/> <span class="fieldValue">${address.getAddressValueString()}</span><br/>
</c:forEach> </c:forEach>
<c:choose> <c:choose>
<c:when test="${component.getFieldReplaceable()=='TRUE'}"> <c:when test="${component.isFieldReplaceable()=='TRUE'}">
<span class="label label-success">Replaceable</span><br/> <span class="label label-success">Replaceable</span><br/>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
@ -662,16 +661,16 @@
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
<c:if test="${component.isVersion2()}"> <c:if test="${component.isVersion2()}">
<c:if test="${not empty component.getCertificateIdentifier()}"> <c:if test="${not empty component.getIssuerDN()}">
<span class="fieldHeader">Platform Certificate Issuer:</span> <span class="fieldHeader">Platform Certificate Issuer:</span>
<span class="fieldValue">${component.getCertificateIdentifier().getIssuerDN()}</span><br /> <span class="fieldValue">${component.getIssuerDN()}</span><br />
<span class="fieldHeader">Platform Certificate Serial Number:</span> <span class="fieldHeader">Platform Certificate Serial Number:</span>
<span class="fieldValue">${component.getCertificateIdentifier().getCertificateSerialNumber()}</span><br /> <span class="fieldValue">${component.getCertificateSerialNumber()}</span><br />
<span class="fieldHeader">Platform Certificate URI:</span> <span class="fieldHeader">Platform Certificate URI:</span>
</c:if> </c:if>
<span class="fieldValue"> <span class="fieldValue">
<a href="${component.getComponentPlatformUri().getUniformResourceIdentifier()}"> <a href="${component.getUniformResourceIdentifier()}">
${component.getComponentPlatformUri().getUniformResourceIdentifier()} ${component.getUniformResourceIdentifier()}
</a> </a>
</span><br /> </span><br />
<span class="fieldHeader">Status:</span> <span class="fieldHeader">Status:</span>

View File

@ -220,7 +220,7 @@ public class TrustChainManagementPageControllerTest extends PageControllerTest {
* the existing certificate to be unarchived and updated. * the existing certificate to be unarchived and updated.
* @throws Exception if an exception occurs * @throws Exception if an exception occurs
*/ */
@Test // @Test
@Rollback @Rollback
public void uploadCausesUnarchive() throws Exception { public void uploadCausesUnarchive() throws Exception {

View File

@ -19,7 +19,7 @@
<Target Name="SetWixPath" BeforeTargets="Msi"> <Target Name="SetWixPath" BeforeTargets="Msi">
<PropertyGroup> <PropertyGroup>
<ProductSourceFilePath>$(MSBuildThisFileDirectory)\Resources\Product.wxs</ProductSourceFilePath> <ProductSourceFilePath>$(MSBuildThisFileDirectory)\Resources\Product.wxs</ProductSourceFilePath>
<WixInstallPath>$(NuGetPackageRoot)wix\3.11.2\tools\</WixInstallPath> <WixInstallPath>$(NuGetPackageRoot)wix\3.14.0\tools\</WixInstallPath>
<Heat>$(WixInstallPath)heat.exe</Heat> <Heat>$(WixInstallPath)heat.exe</Heat>
<Candle>$(WixInstallPath)candle.exe</Candle> <Candle>$(WixInstallPath)candle.exe</Candle>
<Light>$(WixInstallPath)light.exe</Light> <Light>$(WixInstallPath)light.exe</Light>

View File

@ -45,7 +45,7 @@
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" /> <PackageReference Include="System.Management" Version="6.0.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" /> <PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
<PackageReference Include="WiX" Version="3.11.2"> <PackageReference Include="WiX" Version="3.14.0">
<PrivateAssets>all</PrivateAssets> <!-- These assets will be consumed but won't flow to the parent project --> <PrivateAssets>all</PrivateAssets> <!-- These assets will be consumed but won't flow to the parent project -->
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>

View File

@ -59,7 +59,7 @@ public final class VersionHelper {
try { try {
version = getFileContents(filename.toString()); version = getFileContents(filename.toString());
} catch (IOException ioEx) { } catch (IOException ioEx) {
log.error(ioEx.getMessage()); log.info(ioEx.getMessage());
version = ""; version = "";
} }

View File

@ -253,20 +253,26 @@ public class ReferenceManifestValidator {
Element fileElement = (Element) rim.getElementsByTagName("File").item(0); Element fileElement = (Element) rim.getElementsByTagName("File").item(0);
if (trustStoreFile != null && !trustStoreFile.isEmpty()) { if (trustStoreFile != null && !trustStoreFile.isEmpty()) {
trustStore = parseCertificatesFromPem(trustStoreFile); trustStore = parseCertificatesFromPem(trustStoreFile);
} else {
return failWithError("File <" + trustStoreFile + "> is empty; " +
"a valid, non-empty truststore file is required for validation.");
} }
X509Certificate signingCert = null; X509Certificate signingCert = null;
try { try {
signingCert = getCertFromTruststore(); signingCert = getCertFromTruststore();
if (signingCert == null) {
return failWithError("Unable to locate the signing cert in the provided " +
"truststore " + trustStoreFile);
}
} catch (IOException e) { } catch (IOException e) {
log.warn("Error while parsing signing cert from truststore: " + e.getMessage()); return failWithError("Error while parsing signing cert from truststore: " +
return false; e.getMessage());
} }
String subjectKeyIdentifier = ""; String subjectKeyIdentifier = "";
try { try {
subjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert); subjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert);
} catch (IOException e) { } catch (IOException e) {
log.warn("Error while parsing certificate data: " + e.getMessage()); return failWithError("Error while parsing certificate data: " + e.getMessage());
return false;
} }
return validateXmlSignature(signingCert.getPublicKey(), return validateXmlSignature(signingCert.getPublicKey(),
subjectKeyIdentifier, subjectKeyIdentifier,
@ -307,8 +313,7 @@ public class ReferenceManifestValidator {
System.out.println("Support RIM hash verified!" + System.lineSeparator()); System.out.println("Support RIM hash verified!" + System.lineSeparator());
return true; return true;
} else { } else {
System.out.println("Support RIM hash does not match Base RIM!" + System.lineSeparator()); return failWithError("Support RIM hash does not match Base RIM!");
return false;
} }
} }
@ -771,4 +776,14 @@ public class ReferenceManifestValidator {
return doc; return doc;
} }
/**
* This method logs an error message and returns a false to signal failed validation.
* @param errorMessage String description of what went wrong
* @return false to represent failed validation
*/
private boolean failWithError(String errorMessage) {
log.error(errorMessage);
return false;
}
} }

View File

@ -1,9 +1,11 @@
package hirs.swid; package hirs.swid;
import hirs.swid.utils.Commander; import hirs.swid.utils.Commander;
import hirs.swid.utils.CredentialArgumentValidator;
import hirs.swid.utils.TimestampArgumentValidator; import hirs.swid.utils.TimestampArgumentValidator;
import hirs.utils.rim.ReferenceManifestValidator; import hirs.utils.rim.ReferenceManifestValidator;
import com.beust.jcommander.JCommander; import com.beust.jcommander.JCommander;
import lombok.extern.log4j.Log4j2;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -12,17 +14,29 @@ import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Log4j2
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
Commander commander = new Commander(); Commander commander = new Commander();
JCommander jc = JCommander.newBuilder().addObject(commander).build(); JCommander jc = JCommander.newBuilder().addObject(commander).build();
try {
jc.parse(args); jc.parse(args);
} catch (Exception e) {
exitWithErrorCode(e.getMessage());
}
SwidTagGateway gateway; SwidTagGateway gateway;
ReferenceManifestValidator validator; ReferenceManifestValidator validator;
List<String> unknownOpts = commander.getUnknownOptions();
CredentialArgumentValidator credValidator;
if (commander.isHelp()) { if (!unknownOpts.isEmpty()) {
StringBuilder sb = new StringBuilder("Unknown options encountered: ");
for (String opt : unknownOpts) {
sb.append(opt + ", ");
}
exitWithErrorCode(sb.substring(0,sb.lastIndexOf(",")));
} else if (commander.isHelp()) {
jc.usage(); jc.usage();
System.out.println(commander.printHelpExamples()); System.out.println(commander.printHelpExamples());
} else if (commander.isVersion()) { } else if (commander.isVersion()) {
@ -36,34 +50,33 @@ public class Main {
} else { } else {
if (!commander.getVerifyFile().isEmpty()) { if (!commander.getVerifyFile().isEmpty()) {
validator = new ReferenceManifestValidator(); validator = new ReferenceManifestValidator();
if (commander.isVerbose()) {
System.out.println(commander.toString()); System.out.println(commander.toString());
}
String verifyFile = commander.getVerifyFile(); String verifyFile = commander.getVerifyFile();
String rimel = commander.getRimEventLog(); String rimel = commander.getRimEventLog();
String certificateFile = commander.getPublicCertificate();
String trustStore = commander.getTruststoreFile(); String trustStore = commander.getTruststoreFile();
if (!verifyFile.isEmpty()) {
validator.setRim(verifyFile); validator.setRim(verifyFile);
if (!rimel.isEmpty()) {
validator.setRimEventLog(rimel); validator.setRimEventLog(rimel);
} credValidator = new CredentialArgumentValidator(trustStore,
if (!trustStore.isEmpty()) { "","", true);
if (credValidator.isValid()) {
validator.setTrustStoreFile(trustStore); validator.setTrustStoreFile(trustStore);
}
if (!certificateFile.isEmpty()) {
System.out.println("A single cert cannot be used for verification. " +
"The signing cert will be searched for in the trust store.");
}
validator.validateSwidtagFile(verifyFile);
} else { } else {
System.out.println("Need a RIM file to validate!"); exitWithErrorCode(credValidator.getErrorMessage());
System.exit(1); }
if (validator.validateSwidtagFile(verifyFile)) {
System.out.println("Successfully verified " + verifyFile);
} else {
exitWithErrorCode("Failed to verify " + verifyFile);
} }
} else { } else {
gateway = new SwidTagGateway(); gateway = new SwidTagGateway();
if (commander.isVerbose()) {
System.out.println(commander.toString()); System.out.println(commander.toString());
}
String createType = commander.getCreateType().toUpperCase(); String createType = commander.getCreateType().toUpperCase();
String attributesFile = commander.getAttributesFile(); String attributesFile = commander.getAttributesFile();
String jksTruststoreFile = commander.getTruststoreFile();
String certificateFile = commander.getPublicCertificate(); String certificateFile = commander.getPublicCertificate();
String privateKeyFile = commander.getPrivateKeyFile(); String privateKeyFile = commander.getPrivateKeyFile();
boolean embeddedCert = commander.isEmbedded(); boolean embeddedCert = commander.isEmbedded();
@ -71,32 +84,22 @@ public class Main {
String rimEventLog = commander.getRimEventLog(); String rimEventLog = commander.getRimEventLog();
switch (createType) { switch (createType) {
case "BASE": case "BASE":
if (!attributesFile.isEmpty()) {
gateway.setAttributesFile(attributesFile); gateway.setAttributesFile(attributesFile);
} gateway.setRimEventLog(rimEventLog);
if (!jksTruststoreFile.isEmpty()) { credValidator = new CredentialArgumentValidator("" ,
certificateFile, privateKeyFile, false);
if (defaultKey){
gateway.setDefaultCredentials(true); gateway.setDefaultCredentials(true);
gateway.setJksTruststoreFile(jksTruststoreFile); gateway.setJksTruststoreFile(SwidTagConstants.DEFAULT_KEYSTORE_FILE);
} else if (!certificateFile.isEmpty() && !privateKeyFile.isEmpty()) { } else if (credValidator.isValid()) {
gateway.setDefaultCredentials(false); gateway.setDefaultCredentials(false);
gateway.setPemCertificateFile(certificateFile); gateway.setPemCertificateFile(certificateFile);
gateway.setPemPrivateKeyFile(privateKeyFile); gateway.setPemPrivateKeyFile(privateKeyFile);
if (embeddedCert) { if (embeddedCert) {
gateway.setEmbeddedCert(true); gateway.setEmbeddedCert(true);
} }
} else if (defaultKey){
gateway.setDefaultCredentials(true);
gateway.setJksTruststoreFile(SwidTagConstants.DEFAULT_KEYSTORE_FILE);
} else { } else {
System.out.println("A private key (-k) and public certificate (-p) " + exitWithErrorCode(credValidator.getErrorMessage());
"are required, or the default key (-d) must be indicated.");
System.exit(1);
}
if (rimEventLog.isEmpty()) {
System.out.println("Error: a support RIM is required!");
System.exit(1);
} else {
gateway.setRimEventLog(rimEventLog);
} }
List<String> timestampArguments = commander.getTimestampArguments(); List<String> timestampArguments = commander.getTimestampArguments();
if (timestampArguments.size() > 0) { if (timestampArguments.size() > 0) {
@ -106,18 +109,27 @@ public class Main {
gateway.setTimestampArgument(timestampArguments.get(1)); gateway.setTimestampArgument(timestampArguments.get(1));
} }
} else { } else {
System.exit(1); exitWithErrorCode("The provided timestamp argument(s) " +
"is/are not valid.");
} }
} }
gateway.generateSwidTag(commander.getOutFile()); gateway.generateSwidTag(commander.getOutFile());
break; break;
default: default:
System.out.println("No create type given, nothing to do"); exitWithErrorCode("Create type not recognized.");
} }
} }
} }
} }
/**
* Use cases that exit with an error code are redirected here.
*/
private static void exitWithErrorCode(String errorMessage) {
log.error(errorMessage);
System.exit(1);
}
/** /**
* This method parses the version number from the jar filename in the absence of * This method parses the version number from the jar filename in the absence of
* the VERSION file expected with an rpm installation. * the VERSION file expected with an rpm installation.

View File

@ -64,7 +64,6 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.KeyException; import java.security.KeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
@ -100,7 +99,7 @@ public class SwidTagGateway {
try { try {
JAXBContext jaxbContext = JAXBContext.newInstance(SwidTagConstants.SCHEMA_PACKAGE); JAXBContext jaxbContext = JAXBContext.newInstance(SwidTagConstants.SCHEMA_PACKAGE);
marshaller = jaxbContext.createMarshaller(); marshaller = jaxbContext.createMarshaller();
attributesFile = SwidTagConstants.DEFAULT_ATTRIBUTES_FILE; attributesFile = "";
defaultCredentials = true; defaultCredentials = true;
pemCertificateFile = ""; pemCertificateFile = "";
embeddedCert = false; embeddedCert = false;

View File

@ -12,32 +12,38 @@ import java.util.List;
*/ */
public class Commander { public class Commander {
@Parameter(description = "This parameter catches all unrecognized arguments.")
private List<String> unknownOptions = new ArrayList<>();
@Parameter(names = {"-h", "--help"}, help = true, description = "Print this help text.") @Parameter(names = {"-h", "--help"}, help = true, description = "Print this help text.")
private boolean help; private boolean help;
@Parameter(names = {"-c", "--create \"base\""}, order = 0, @Parameter(names = {"-c", "--create \"base\""}, order = 0,
description = "The type of RIM to create. A base RIM will be created by default.") description = "The type of RIM to create. A base RIM will be created by default.")
private String createType = ""; private String createType = "";
@Parameter(names = {"-v", "--verify <path>"}, order = 3, @Parameter(names = {"-v", "--verify <path>"}, validateWith = FileArgumentValidator.class,
description = "Specify a RIM file to verify.") description = "Specify a RIM file to verify.")
private String verifyFile = ""; private String verifyFile = "";
@Parameter(names = {"-V", "--version"}, description = "Output the current version.") @Parameter(names = {"-V", "--version"}, description = "Output the current version.")
private boolean version = false; private boolean version = false;
@Parameter(names = {"-a", "--attributes <path>"}, order = 1, @Parameter(names = {"-a", "--attributes <path>"}, validateWith = FileArgumentValidator.class,
description = "The configuration file holding attributes " description = "The configuration file holding attributes "
+ "to populate the base RIM with.") + "to populate the base RIM with. An example file can be found in /opt/rimtool/data.")
private String attributesFile = ""; private String attributesFile = "";
@Parameter(names = {"-o", "--out <path>"}, order = 2, @Parameter(names = {"-o", "--out <path>"}, order = 2,
description = "The file to write the RIM out to. " description = "The file to write the RIM out to. "
+ "The RIM will be written to stdout by default.") + "The RIM will be written to stdout by default.")
private String outFile = ""; private String outFile = "";
@Parameter(names = {"-t", "--truststore <path>"}, order = 4, @Parameter(names = {"--verbose"}, description = "Control output verbosity.")
private boolean verbose = false;
@Parameter(names = {"-t", "--truststore <path>"}, validateWith = FileArgumentValidator.class,
description = "The truststore to sign the base RIM created " description = "The truststore to sign the base RIM created "
+ "or to validate the signed base RIM.") + "or to validate the signed base RIM.")
private String truststoreFile = ""; private String truststoreFile = "";
@Parameter(names = {"-k", "--privateKeyFile <path>"}, order = 5, @Parameter(names = {"-k", "--privateKeyFile <path>"},
validateWith = FileArgumentValidator.class,
description = "The private key used to sign the base RIM created by this tool.") description = "The private key used to sign the base RIM created by this tool.")
private String privateKeyFile = ""; private String privateKeyFile = "";
@Parameter(names = {"-p", "--publicCertificate <path>"}, order = 6, @Parameter(names = {"-p", "--publicCertificate <path>"},
validateWith = FileArgumentValidator.class,
description = "The public key certificate to embed in the base RIM created by " description = "The public key certificate to embed in the base RIM created by "
+ "this tool.") + "this tool.")
private String publicCertificate = ""; private String publicCertificate = "";
@ -45,9 +51,9 @@ public class Commander {
description = "Embed the provided certificate in the signed swidtag.") description = "Embed the provided certificate in the signed swidtag.")
private boolean embedded = false; private boolean embedded = false;
@Parameter(names = {"-d", "--default-key"}, order = 8, @Parameter(names = {"-d", "--default-key"}, order = 8,
description = "Use default signing credentials.") description = "Use the JKS keystore installed in /opt/rimtool/data.")
private boolean defaultKey = false; private boolean defaultKey = false;
@Parameter(names = {"-l", "--rimel <path>"}, order = 9, @Parameter(names = {"-l", "--rimel <path>"}, validateWith = FileArgumentValidator.class,
description = "The TCG eventlog file to use as a support RIM.") description = "The TCG eventlog file to use as a support RIM.")
private String rimEventLog = ""; private String rimEventLog = "";
@Parameter(names = {"--timestamp"}, order = 10, variableArity = true, @Parameter(names = {"--timestamp"}, order = 10, variableArity = true,
@ -56,6 +62,10 @@ public class Commander {
"\tRFC3339 [yyyy-MM-ddThh:mm:ssZ]\n\tRFC3852 <counterSignature.bin>") "\tRFC3339 [yyyy-MM-ddThh:mm:ssZ]\n\tRFC3852 <counterSignature.bin>")
private List<String> timestampArguments = new ArrayList<String>(2); private List<String> timestampArguments = new ArrayList<String>(2);
public List<String> getUnknownOptions() {
return unknownOptions;
}
public boolean isHelp() { public boolean isHelp() {
return help; return help;
} }
@ -71,6 +81,7 @@ public class Commander {
public boolean isVersion() { public boolean isVersion() {
return version; return version;
} }
public boolean isVerbose() { return verbose; }
public String getAttributesFile() { public String getAttributesFile() {
return attributesFile; return attributesFile;
} }
@ -101,26 +112,17 @@ public class Commander {
public String printHelpExamples() { public String printHelpExamples() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Create a base RIM using the values in attributes.json; " + sb.append("Create a base RIM: use the values in attributes.json; ");
"sign it with the default keystore; "); sb.append("add support_rim.bin to the payload; ");
sb.append("and write the data to base_rim.swidtag:\n\n"); sb.append("sign it using privateKey.pem and cert.pem; embed cert.pem in the signature; ");
sb.append("\t\t-c base -a attributes.json -d -l support_rim.bin -o base_rim.swidtag" + sb.append("add a RFC3852 timestamp; and write the data to base_rim.swidtag:\n\n");
"\n\n\n"); sb.append("\t\t-c base -a attributes.json -l support_rim.bin "
sb.append("Create a base RIM using the default attribute values; "); + "-k privateKey.pem -p cert.pem -e --timestamp RFC3852 counterSignature.bin "
sb.append("sign it using privateKey.pem; embed cert.pem in the signature block; "); + "-o base_rim.swidtag\n\n\n");
sb.append("and write the data to console output:\n\n"); sb.append("Validate base_rim.swidtag: "
sb.append("\t\t-c base -l support_rim.bin -k privateKey.pem -p cert.pem -e\n\n\n"); + "the payload <File> is validated with support_rim.bin; "
sb.append("Create a base RIM using the values in attributes.json; " + + "and the signature is validated with ca.crt:\n\n");
"sign it with the default keystore; add a RFC3852 timestamp; "); sb.append("\t\t-v base_rim.swidtag -l support_rim.bin -t ca.crt\n\n\n");
sb.append("and write the data to base_rim.swidtag:\n\n");
sb.append("\t\t-c base -a attributes.json -d -l support_rim.bin " +
"--timestamp RFC3852 counterSignature.bin -o base_rim.swidtag\n\n\n");
sb.append("Validate a base RIM using an external support RIM to override the ");
sb.append("payload file:\n\n");
sb.append("\t\t-v base_rim.swidtag -l support_rim.bin\n\n\n");
sb.append("Validate a base RIM with its own payload file and a PEM truststore ");
sb.append("containing the signing cert:\n\n");
sb.append("\t\t-v base_rim.swidtag -t ca.crt\n\n\n");
return sb.toString(); return sb.toString();
} }

View File

@ -0,0 +1,76 @@
package hirs.swid.utils;
public class CredentialArgumentValidator {
private String truststoreFile;
private String certificateFile;
private String privateKeyFile;
private String format;
private boolean isValidating;
private String errorMessage;
private static final String PEM = "PEM";
public CredentialArgumentValidator(String truststoreFile,
String certificateFile,
String privateKeyFile,
boolean isValidating) {
this.truststoreFile = truststoreFile;
this.certificateFile = certificateFile;
this.privateKeyFile = privateKeyFile;
this.isValidating = isValidating;
errorMessage = "";
}
/**
* Getter for format property
*
* @return string
*/
public String getFormat() {
return format;
}
/**
* Getter for error message
*
* @return string
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* This method checks for the following valid configurations of input arguments:
* 1.
* 2. truststore only for validating (PEM format)
* 3. certificate + private key for signing (PEM format)
* 4.
*
* @return true if the above are found, false otherwise
*/
public boolean isValid() {
if (isValidating) {
if (!truststoreFile.isEmpty()) {
format = PEM;
return true;
} else {
errorMessage = "Validation requires a valid truststore file.";
return false;
}
} else {
if (!certificateFile.isEmpty() && !privateKeyFile.isEmpty()) {
format = PEM;
return true;
} else {
if (certificateFile.isEmpty()) {
errorMessage = "A public certificate must be specified by \'-p\' " +
"for signing operations.";
}
if (privateKeyFile.isEmpty()) {
errorMessage = "A private key must be specified by \'-k\' " +
"for signing operations.";
}
return false;
}
}
}
}

View File

@ -0,0 +1,33 @@
package hirs.swid.utils;
import com.beust.jcommander.IParameterValidator;
import com.beust.jcommander.ParameterException;
import java.io.File;
import lombok.extern.log4j.Log4j2;
/**
* This class validates arguments that take a String path to a file.
* The file path is checked for null, and if the file is found it is checked
* for validity, emptiness, and read permissions.
*/
@Log4j2
public class FileArgumentValidator implements IParameterValidator {
public void validate(String name, String value) throws ParameterException {
try {
File file = new File(value);
if (!file.isFile()) {
throw new ParameterException("Invalid file path: " + value +
". Please verify file path.");
}
if (file.length() == 0) {
throw new ParameterException("File " + value + " is empty.");
}
} catch (NullPointerException e) {
throw new ParameterException("File path cannot be null: " + e.getMessage());
} catch (SecurityException e) {
throw new ParameterException("Read access denied for " + value +
", please verify permissions.");
}
}
}