added in finished files

This commit is contained in:
Cyrus 2023-03-06 20:56:34 -05:00
parent 468cbc0797
commit 17a8732908
97 changed files with 12422 additions and 0 deletions

View File

@ -0,0 +1,52 @@
plugins {
id 'java'
id 'io.spring.dependency-management' version '1.1.0'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
flatDir { dirs "lib" }
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
implementation project(':HIRS_Utils')
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.0.1'
implementation 'commons-codec:commons-codec:1.15'
implementation 'com.eclipsesource.minimal-json:minimal-json:0.9.5'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.bouncycastle:bcmail-jdk15on:1.70'
implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0'
// implementation libs.jackson_core
// implementation libs.jackson_databind
implementation 'com.fasterxml.jackson.core:jackson-core:2.14.2'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0'
implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
implementation 'org.apache.logging.log4j:log4j-api:2.19.0'
// spring management
compileOnly libs.lombok
implementation libs.lombok
annotationProcessor libs.lombok
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,223 @@
package hirs.attestationca.persist;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
/**
* The class handles the flags that ignore certain PCRs for validation.
*/
@Log4j2
@NoArgsConstructor
public class PCRQuoteValidator {
/**
* Minimum possible value for a PCR ID. This is 0.
*/
public static final int MIN_PCR_ID = 0;
/**
* Maximum possible value for a PCR ID. This is 23.
*/
public static final int MAX_PCR_ID = 23;
private static final int NUM_TO_SKIP = 1;
private static final int NUM_OF_TBOOT_PCR = 3;
// PCR 5-16
private static final int PXE_PCR_START = 5;
private static final int PXE_PCR_END = 16;
// PCR 10
private static final int IMA_PCR = 10;
// PCR 17-19
private static final int TBOOT_PCR_START = 17;
private static final int TBOOT_PCR_END = 19;
// PCR 5
private static final int GPT_PCR = 5;
private static final int IMA_MASK = 0xfffbff;
// Event Log Event Types
private static final String EVT_EFI_BOOT = "EV_EFI_BOOT_SERVICES_APPLICATION";
private static final String EVT_EFI_VAR = "EV_EFI_VARIABLE_BOOT";
private static final String EVT_EFI_GPT = "EV_EFI_GPT_EVENT";
private static final String EVT_EFI_CFG = "EV_EFI_VARIABLE_DRIVER_CONFIG";
private String[] baselinePCRS = new String[MAX_PCR_ID + 1];
@Getter
@Setter
private SupplyChainSettings settings;
/**
* Constructor to parse PCR values.
* @param pcrValues pcrValues RIM provided baseline PCRs
* @param settings settings for the supply chain portal settings for provisioning
*/
public PCRQuoteValidator(final String[] pcrValues,
final SupplyChainSettings settings) {
if (pcrValues != null) {
baselinePCRS = new String[MAX_PCR_ID + 1];
for (int i = 0; i <= MAX_PCR_ID; i++) {
baselinePCRS[i] = pcrValues[i];
}
}
this.settings = settings;
}
/**
* Getter for the array of baseline PCRs.
* @return instance of the PCRs.
*/
public String[] getBaselinePCRS() {
return baselinePCRS.clone();
}
/**
* Setter for the array of baseline PCRs.
* @param baselinePCRS instance of the PCRs.
*/
public void setBaselinePCRS(final String[] baselinePCRS) {
this.baselinePCRS = baselinePCRS.clone();
}
/**
* Compares the baseline pcr list and the quote pcr list. If the
* ignore flags are set, 10 and 17-19 will be skipped for comparison.
*
* @param storedPCRS non-baseline pcr list
* @return a StringBuilder that is empty if everything passes.
*/
public StringBuilder validatePCRS(final String[] storedPCRS) {
StringBuilder sb = new StringBuilder();
String failureMsg = "PCR %d does not match%n";
if (storedPCRS[0] == null || storedPCRS[0].isEmpty()) {
sb.append("failureMsg");
} else {
for (int i = 0; i <= MAX_PCR_ID; i++) {
if (settings.isIgnoreImaEnabled() && i == IMA_PCR) {
log.info("PCR Policy IMA Ignore enabled.");
i += NUM_TO_SKIP;
}
if (settings.isIgnoretBootEnabled() && i == TBOOT_PCR_START) {
log.info("PCR Policy TBoot Ignore enabled.");
i += NUM_OF_TBOOT_PCR;
}
if (settings.isIgnoreGptEnabled() && i == GPT_PCR) {
log.info("PCR Policy GPT Ignore enabled.");
i += NUM_TO_SKIP;
}
if (!baselinePCRS[i].equals(storedPCRS[i])) {
//error
log.error(String.format("%s =/= %s", baselinePCRS[i], storedPCRS[i]));
sb.append(String.format(failureMsg, i));
}
}
}
return sb;
}
/**
* Checks that the expected FM events occurring. There are policy options that
* will ignore certain PCRs, Event Types and Event Variables present.
* @param tcgMeasurementLog Measurement log from the client
* @param eventValueMap The events stored as baseline to compare
* @return the events that didn't pass
*/
// public List<TpmPcrEvent> validateTpmEvents(final TCGEventLog tcgMeasurementLog,
// final Map<String, ReferenceDigestValue> eventValueMap) {
// List<TpmPcrEvent> tpmPcrEvents = new LinkedList<>();
// for (TpmPcrEvent tpe : tcgMeasurementLog.getEventList()) {
// if (enableIgnoreIma && tpe.getPcrIndex() == IMA_PCR) {
// log.info(String.format("IMA Ignored -> %s", tpe));
// } else if (enableIgnoretBoot && (tpe.getPcrIndex() >= TBOOT_PCR_START
// && tpe.getPcrIndex() <= TBOOT_PCR_END)) {
// log.info(String.format("TBOOT Ignored -> %s", tpe));
// } else if (enableIgnoreOsEvt && (tpe.getPcrIndex() >= PXE_PCR_START
// && tpe.getPcrIndex() <= PXE_PCR_END)) {
// log.info(String.format("OS Evt Ignored -> %s", tpe));
// } else {
// if (enableIgnoreGpt && tpe.getEventTypeStr().contains(EVT_EFI_GPT)) {
// log.info(String.format("GPT Ignored -> %s", tpe));
// } else if (enableIgnoreOsEvt && (tpe.getEventTypeStr().contains(EVT_EFI_BOOT)
// || tpe.getEventTypeStr().contains(EVT_EFI_VAR))) {
// log.info(String.format("OS Evt Ignored -> %s", tpe));
// } else if (enableIgnoreOsEvt && (tpe.getEventTypeStr().contains(EVT_EFI_CFG)
// && tpe.getEventContentStr().contains("SecureBoot"))) {
// log.info(String.format("OS Evt Config Ignored -> %s", tpe));
// } else {
// if (!eventValueMap.containsKey(tpe.getEventDigestStr())) {
// tpmPcrEvents.add(tpe);
// }
// }
// }
// }
//
// return tpmPcrEvents;
// }
/**
* Compares hashes to validate the quote from the client.
*
* @param tpmQuote the provided quote
* @param storedPCRS values from the RIM file
* @return true if validated, false if not
*/
// public boolean validateQuote(final byte[] tpmQuote, final String[] storedPCRS) {
// System.out.println("Validating quote from associated device.");
// boolean validated = false;
// short localityAtRelease = 0;
// String quoteString = new String(tpmQuote, StandardCharsets.UTF_8);
// int pcrMaskSelection = PcrSelection.ALL_PCRS_ON;
//
// if (enableIgnoreIma) {
// pcrMaskSelection = IMA_MASK;
// }
//
// ArrayList<TPMMeasurementRecord> measurements = new ArrayList<>();
//
// try {
// for (int i = 0; i < storedPcrs.length; i++) {
// if (i == IMA_PCR && enableIgnoreIma) {
// log.info("Ignore IMA PCR policy is enabled.");
// } else {
// measurements.add(new TPMMeasurementRecord(i, storedPcrs[i]));
// }
// }
// } catch (DecoderException deEx) {
// //error
// System.out.println(deEx);
// }
//
// PcrSelection pcrSelection = new PcrSelection(pcrMaskSelection);
// PcrComposite pcrComposite = new PcrComposite(pcrSelection);
// PcrInfoShort pcrInfoShort = new PcrInfoShort(pcrSelection,
// localityAtRelease,
// tpmQuote, pcrComposite);
//
// try {
// /**
// * The calculated string is being used in the contains method
// * because the TPM Quote's hash isn't just for PCR values,
// * it contains the calculated digest of the PCRs, along with
// * other information.
// */
// String calculatedString = Hex.encodeHexString(
// pcrInfoShort.getCalculatedDigest());
// validated = quoteString.contains(calculatedString);
// if (!validated) {
// // warn
// System.out.println(calculatedString + " not found in " + quoteString);
// }
// } catch (NoSuchAlgorithmException naEx) {
// // error
// System.out.println(naEx);
// }
//
// return validated;
// }
}

View File

@ -0,0 +1,100 @@
package hirs.attestationca.persist.entity;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import lombok.ToString;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;
import org.hibernate.annotations.JdbcTypeCode;
import java.io.Serializable;
import java.util.Date;
import java.util.UUID;
/**
* An abstract database entity.
*/
@ToString
@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
/**
* static value for the length of a status message for objects that
* can have extremely long values, potentially.
*/
protected static final int RESULT_MESSAGE_LENGTH = 1000000;
@Id
@Column(name = "id")
@GeneratedValue(generator = "uuid2", strategy=GenerationType.AUTO)
@JdbcTypeCode(java.sql.Types.VARCHAR)
@Getter
private UUID id;
@Column (name = "create_time")
@ColumnDefault(value = "CURRENT_TIMESTAMP")
@Generated(GenerationTime.INSERT)
private Date createTime;// = new Date();
/**
* Default empty constructor is required for Hibernate. It is protected to
* prevent code from calling it directly.
*/
protected AbstractEntity() {
super();
}
/**
* Setter for the UUID that can not be null
* and can not be overridden.
* @param id - primary able key
*/
public void setId(UUID id) {
if (id != null) {
this.id = id;
}
}
/**
* Returns the creation time of this entity.
*
* @return creation time
*/
public Date getCreateTime() {
return (Date) createTime.clone();
}
/**
* Reset the creation time to the current time.
*/
public void resetCreateTime() {
createTime.setTime(new Date().getTime());
}
@Override
public int hashCode() {
if (id != null) {
return id.hashCode();
}
return super.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(this.getClass().equals(obj.getClass()))) {
return false;
}
return this.hashCode() == obj.hashCode();
}
}

View File

@ -0,0 +1,88 @@
package hirs.attestationca.persist.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
* The <code>Appraiser</code> class represents an appraiser that can appraise a <code>Report</code>.
* <code>Appraiser</code>s are invoked to validate the integrity of client's platform. An
* <code>Appraiser</code> does this by examining a <code>Report</code> sent from the client's
* machine.
* <p>
* Supported <code>Report</code> types are kept track of in three ways: <ul> <li>The type of report
* received for appraisal is getAppraiseReportType() (e.g. the <code>DeviceInfoAppraiser</code>
* takes in a <code>DeviceInfoReport</code> and the <code>TPMAppraiser</code> takes in an
* <code>IntegrityReport</code>)</li> <li>The type requested in getReportRequest is
* getRequestReportType(). This tends to be the specific report type for that type of appraiser
* (e.g. the <code>IMAAppraiser</code> requests an <code>IMAReport</code> and the
* <code>TPMAppraiser</code> requests a <code>TPMReport</code>)</li> <li>The set of types this
* appraiser relies on extracting from the top-level report is getRequiredReportTypes() (e.g. if the
* top-level report is <code>IntegrityReport</code> then the <code>IMAAppraiser</code> needs to
* extract both a <code>DeviceInfoReport</code> and a <code>IMAReport</code> from the
* <code>IntegrityReport</code>)</li> </ul>
*/
@Entity
@Table(name = "Appraiser")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@EqualsAndHashCode(callSuper = false)
public class Appraiser {
/**
* Name set for every instance of <code>TPMAppraiser</code>.
*/
public static final String TPM_NAME = "TPM Appraiser";
/**
* Name set for every instance of <code>SupplyChainAppraiser</code>.
*/
public static final String SC_NAME = "Supply Chain Appraiser";
/**
* Name set for every instance of <code>IMAAppraiser</code>.
*/
public static final String IMA_NAME = "IMA Appraiser";
/**
* Name set for every instance of <code>HIRSAppraiser</code>.
*/
public static final String HIRS_NAME = "HIRS Appraiser";
/**
* Name set for every instance of <code>DeviceInfoAppraiser</code>.
*/
public static final String DI_NAME = "Device Info Appraiser";
@Getter
@ToString.Exclude
@EqualsAndHashCode.Exclude
@Id
@Column(name = "Appraiser_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Getter
@Setter
@Column(nullable = false, unique = true)
private String name;
/**
* Creates a new <code>Appraiser</code> with the specified name. The name should be universally
* unique as this is how other components will identify <code>Appraiser</code>s. Web portals,
* for instance, could display a list of <code>Appraiser</code> names to display which
* <code>Appraiser</code>s are available.
* <p>
* The name will be tested for uniqueness when it is added to a repository. It is not tested for
* uniqueness in the class.
*
* @param name unique name
*/
public Appraiser(final String name) {
this.name = name;
}
}

View File

@ -0,0 +1,95 @@
package hirs.attestationca.persist.entity;
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import lombok.ToString;
import java.util.Date;
/**
* An abstract archivable entity that can be deleted.
*/
@ToString
@Getter
@MappedSuperclass
public abstract class ArchivableEntity extends AbstractEntity {
/**
* Defining the size of a message field for error display.
*/
public static final int MAX_MESSAGE_LENGTH = 2400;
@Column(name = "archived_time")
private Date archivedTime;
@Column(name = "archived_description")
private String archivedDescription;
/**
* Default empty constructor is required for Hibernate. It is protected to
* prevent code from calling it directly.
*/
protected ArchivableEntity() {
super();
}
/**
* Return the boolean representing whether or not this entity has been soft-deleted.
*
* @return true if this entity has been soft-deleted, false otherwise
*/
public final boolean isArchived() {
return archivedTime != null;
}
/**
* Signals that this entity has been archived, by setting the archivedTime to the current date
* and time.
*
* @return
* true if time was null and date was set.
* false is archived time is already set, signifying the entity has been archived.
*/
public final boolean archive() {
if (this.archivedTime == null) {
this.archivedTime = new Date();
return true;
}
return false;
}
/**
* Sets a description for the resolution if one is provided. This is done for accounting
* purposes so the reason for action taken can be referenced.
*
* @param description - description of the action taken for resolution
* @return
* boolean result is dependent on the return value of the archive() method
*/
public final boolean archive(final String description) {
if (archive()) {
this.archivedDescription = description;
return true;
} else {
return false;
}
}
/**
* Sets the archivedTime to null. The archivedTime being null signifies that the entity has
* not been archived. If the time is already null then this call was unnecessary.
*
* @return
* true if the time is changed to null.
* false if time was already set to null.
*/
public final boolean restore() {
if (this.archivedTime != null) {
this.archivedTime = null;
this.archivedDescription = null;
return true;
}
return false;
}
}

View File

@ -0,0 +1,72 @@
package hirs.attestationca.persist.entity;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.MappedSuperclass;
/**
* The <code>Policy</code> class represents a policy. This is an abstract class
* for representing the rules for which an <code>Appraiser</code> should
* evaluate a <code>Report</code>. A typical <code>Policy</code> will contain a
* <code>Baseline</code> at the very least. A <code>Policy</code> is identified
* by its name, so the name for a <code>Policy</code> must be unique.
*/
@Inheritance(strategy = InheritanceType.JOINED)
@Access(AccessType.FIELD)
@MappedSuperclass
public abstract class Policy extends UserDefinedEntity {
/**
* Default empty constructor is required for Hibernate. It is protected to
* prevent code from calling it directly.
*/
protected Policy() {
super();
}
/**
* Creates a new <code>Policy</code> with the specified name.
*
* @param name
* name
*/
public Policy(final String name) {
super(name);
}
/**
* Creates a new <code>Policy</code> with the specified name and
* description.
*
* @param name
* name (required)
* @param description
* description (may be null)
*/
public Policy(final String name, final String description) {
super(name, description);
}
/**
* Returns true if this object has been persisted. Used in determining whether
* an Appraiser should request the full Policy (and baselines) for appraisal
*
* @return true if this object has been persisted; false otherwise
*/
public final boolean isPersisted() {
return getId() != null;
}
/**
* When {@link Policy} are serialized to be sent to the browser, this can be used
* to determine the type of {@link Policy}.
*
* @return The class name for the {@link Policy}
*/
public String getType() {
return this.getClass().getSimpleName();
}
}

View File

@ -0,0 +1,46 @@
package hirs.attestationca.persist.entity;
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* An abstract archivable entity that can be given a user-defined name and description.
*/
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@MappedSuperclass
public abstract class UserDefinedEntity extends ArchivableEntity {
@Column(nullable = false, unique = true)
private String name;
@ToString.Exclude
@EqualsAndHashCode.Exclude
@Column(nullable = false, unique = false)
private String description = "";
/**
* Default empty constructor is required for Hibernate. It is protected to
* prevent code from calling it directly.
*/
protected UserDefinedEntity() {
super();
}
/**
* Creates a new entity with the specified name.
*
* @param name name
*/
public UserDefinedEntity(final String name) {
this(name, "");
}
}

View File

@ -0,0 +1,11 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface CertificateRepository extends JpaRepository<Certificate, UUID> {
}

View File

@ -0,0 +1,13 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.Device;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.UUID;
@Repository
public interface DeviceRepository extends JpaRepository<Device, UUID> {
List<Device> findByName(String deviceName);
}

View File

@ -0,0 +1,11 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface ReferenceManifestRepository extends JpaRepository<ReferenceManifest, UUID> {
}

View File

@ -0,0 +1,12 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface SettingsRepository extends JpaRepository<SupplyChainSettings, UUID> {
SupplyChainSettings findByName(String name);
}

View File

@ -0,0 +1,4 @@
/**
* This package has objects for hibernate entity.
*/
package hirs.attestationca.persist.entity;

View File

@ -0,0 +1,63 @@
package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.AbstractEntity;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.enums.HealthStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.sql.Timestamp;
@Entity
@Table(name = "Device")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Device extends AbstractEntity {
@Column(name = "name", unique = true)
private String name;
// @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
// optional = true, orphanRemoval = true)
// private DeviceInfoReport deviceInfo;
@Column
@Enumerated(EnumType.ORDINAL)
private HealthStatus healthStatus;
@Column
@Enumerated(EnumType.ORDINAL)
private AppraisalStatus.Status supplyChainValidationStatus;
/**
* Time stamp for the report.
*/
@Column(name = "last_report_timestamp")
private Timestamp lastReportTimestamp;
@Column(name = "is_state_overridden")
private boolean isStateOverridden;
@Column(name = "state_override_reason")
private String overrideReason;
@Column(name = "summary_id")
private String summaryId;
public String toString() {
return String.format("Device Name: %s%nStatus: %s%nSummary: %s",
name, healthStatus.getStatus(),
// supplyChainValidationStatus.toString(),
summaryId);
}
}

View File

@ -0,0 +1,72 @@
package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.ArchivableEntity;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.JdbcTypeCode;
import java.util.UUID;
/**
* This class represents that actual entry in the Support RIM.
* Digest Value, Event Type, index, RIM Tagid
*/
@ToString @EqualsAndHashCode(callSuper = false)
@Setter @Getter
@Entity
@Table(name = "ReferenceDigestValue")
@Access(AccessType.FIELD)
public class ReferenceDigestValue extends ArchivableEntity {
// @Type(type = "uuid-char")
@JdbcTypeCode(java.sql.Types.VARCHAR)
@Column
private UUID baseRimId;
// @Type(type = "uuid-char")
@JdbcTypeCode(java.sql.Types.VARCHAR)
@Column
private UUID supportRimId;
@Column(nullable = false)
private String manufacturer;
@Column(nullable = false)
private String model;
@Column(nullable = false)
private int pcrIndex;
@Column(nullable = false)
private String digestValue;
@Column(nullable = false)
private String eventType;
@Column(columnDefinition = "blob", nullable = true)
private byte[] contentBlob;
@Column(nullable = false)
private boolean matchFail;
@Column(nullable = false)
private boolean patched = false;
@Column(nullable = false)
private boolean updated = false;
/**
* Default constructor necessary for Hibernate.
*/
protected ReferenceDigestValue() {
super();
this.baseRimId = null;
this.supportRimId = null;
this.manufacturer = "";
this.model = "";
this.pcrIndex = -1;
this.digestValue = "";
this.eventType = "";
this.matchFail = false;
this.patched = false;
this.updated = false;
this.contentBlob = null;
}
}

View File

@ -0,0 +1,156 @@
package hirs.attestationca.persist.entity.userdefined;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Preconditions;
import hirs.attestationca.persist.entity.ArchivableEntity;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Hex;
import org.hibernate.annotations.JdbcTypeCode;
import javax.xml.XMLConstants;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
/**
* This class represents the Reference Integrity Manifest object that will be
* loaded into the DB and displayed in the ACA.
*/
@Getter @Setter @ToString
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@Log4j2
@Entity
@Table(name = "ReferenceManifest")
@Access(AccessType.FIELD)
public class ReferenceManifest extends ArchivableEntity {
/**
* Holds the name of the 'hexDecHash' field.
*/
public static final String HEX_DEC_HASH_FIELD = "hexDecHash";
/**
* String for display of a Base RIM.
*/
public static final String BASE_RIM = "Base";
/**
* String for display of a Support RIM.
*/
public static final String SUPPORT_RIM = "Support";
/**
* String for display of a Support RIM.
*/
public static final String MEASUREMENT_RIM = "Measurement";
/**
* String for the xml schema ios standard.
*/
public static final String SCHEMA_STATEMENT = "ISO/IEC 19770-2:2015 Schema (XSD 1.0) "
+ "- September 2015, see http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
/**
* String for the xml schema URL file name.
*/
public static final String SCHEMA_URL = "swid_schema.xsd";
/**
* String for the language type for the xml schema.
*/
public static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI;
/**
* String for the package location of the xml generated java files.
*/
public static final String SCHEMA_PACKAGE = "hirs.utils.xjc";
@EqualsAndHashCode.Include
@Column(columnDefinition = "mediumblob", nullable = false)
private byte[] rimBytes;
@EqualsAndHashCode.Include
@Column(nullable = false)
private String rimType = "Base";
@Column
private String tagId = null;
@Column
private boolean swidPatch = false;
@Column
private boolean swidSupplemental = false;
@Column
private String platformManufacturer = null;
@Column
private String platformManufacturerId = null;
@Column
private String swidTagVersion = null;
@Column
private String swidVersion = null;
@Column
private String platformModel = null;
@Column(nullable = false)
private String fileName = null;
// @Type(type="uuid-char")
@JdbcTypeCode(java.sql.Types.VARCHAR)
@Column
private UUID associatedRim;
@Column
private String deviceName;
@Column
private String hexDecHash = "";
@Column
private String eventLogHash = "";
/**
* Default constructor necessary for Hibernate.
*/
protected ReferenceManifest() {
super();
this.rimBytes = null;
this.rimType = null;
this.platformManufacturer = null;
this.platformManufacturerId = null;
this.platformModel = null;
this.fileName = BASE_RIM;
this.tagId = null;
this.associatedRim = null;
}
/**
* Default constructor for ingesting the bytes of the file content.
* @param rimBytes - file contents.
*/
public ReferenceManifest(final byte[] rimBytes) {
Preconditions.checkArgument(rimBytes != null,
"Cannot construct a RIM from a null byte array");
Preconditions.checkArgument(rimBytes.length > 0,
"Cannot construct a RIM from an empty byte array");
this.rimBytes = rimBytes.clone();
MessageDigest digest = null;
this.hexDecHash = "";
try {
digest = MessageDigest.getInstance("SHA-256");
this.hexDecHash = Hex.encodeHexString(
digest.digest(rimBytes));
} catch (NoSuchAlgorithmException noSaEx) {
log.error(noSaEx);
}
}
/**
* Getter for the Reference Integrity Manifest as a byte array.
*
* @return array of bytes
*/
@JsonIgnore
public byte[] getRimBytes() {
if (this.rimBytes != null) {
return this.rimBytes.clone();
}
return null;
}
}

View File

@ -0,0 +1,41 @@
package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.AbstractEntity;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Entity;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
/**
* A <code>Report</code> represents an integrity report to be appraised by an
* <code>Appraiser</code>. An <code>Appraiser</code> validates the integrity of
* a client's platform with an integrity report. Example reports include an IMA
* report and TPM report.
* <p>
* This <code>Report</code> class contains minimal information because each
* report is vastly different. There is an identification number in case the
* <code>Report</code> is stored in a database, and there is a report type. The
* report type is used to determine which <code>Appraiser</code>s can appraise
* the report.
*/
@Entity
@Access(AccessType.FIELD)
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Report extends AbstractEntity {
/**
* Default constructor.
*/
protected Report() {
super();
}
/**
* Returns a <code>String</code> that indicates this report type. The report
* type is used to find an <code>Appraiser</code> that can appraise this
* <code>Report</code>.
*
* @return report type
*/
public abstract String getReportType();
}

View File

@ -0,0 +1,123 @@
package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.UserDefinedEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* Class represents Supply Chain policy. Supply Chain Policy identifies the methods in
* SupplyChainValidator that should be used in order to validate a supply chain.
* By default, the policy does not enable any validations.
*/
@Table(name = "SupplyChainSettings")
@Getter
@Setter
@Entity
@ToString(callSuper = true)
public class SupplyChainSettings extends UserDefinedEntity {
/**
* Name of the default Supply Chain Policy.
*/
public static final String DEFAULT_POLICY = "Default Supply Chain Policy";
/**
* Number of days in 10 years.
*/
public static final String TEN_YEARS = "3651";
/**
* Number of days in 1 year.
*/
public static final String YEAR = "365";
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ecValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean pcValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean pcAttributeValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean firmwareValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean utcValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean expiredCertificateValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean replaceEC = false;
@Column(nullable = false, columnDefinition = "boolean default true")
private boolean issueAttestationCertificate = true;
@Column(nullable = false, columnDefinition = "boolean default true")
private boolean issueDevIdCertificate = true;
@Column(nullable = false)
private String validityDays = TEN_YEARS;
@Column(nullable = false)
private String devIdValidityDays = TEN_YEARS;
@Column(nullable = false)
private String reissueThreshold = YEAR;
@Column(nullable = false)
private String devIdReissueThreshold = YEAR;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean generateOnExpiration = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean devIdExpirationFlag = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ignoreImaEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ignoretBootEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean linuxOs = false;
@Column(nullable = false, columnDefinition = "boolean default true")
private boolean ignoreGptEnabled = true;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ignoreOsEvtEnabled = false;
/**
* Default constructor necessary for Hibernate.
*/
protected SupplyChainSettings() {
super();
}
/**
* Constructor used to initialize SupplyChainSettings object.
*
* @param name
* A name used to uniquely identify and reference the Supply Chain policy.
*/
public SupplyChainSettings(final String name) {
super(name);
}
/**
* Constructor used to initialize SupplyChainSettings object.
*
* @param name
* A name used to uniquely identify and reference the supply chain policy.
* @param description
* Optional description of the policy that can be added by the user
*/
public SupplyChainSettings(final String name, final String description) {
super(name, description);
}
}

View File

@ -0,0 +1,151 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import lombok.Getter;
import org.apache.commons.codec.binary.Hex;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
/**
* This class persists Certificate Authority credentials by extending the base Certificate
* class with fields unique to CA credentials.
*/
@Entity
public class CertificateAuthorityCredential extends Certificate {
@SuppressWarnings("PMD.AvoidUsingHardCodedIP")
private static final String SUBJECT_KEY_IDENTIFIER_EXTENSION = "2.5.29.14";
/**
* Holds the name of the 'subjectKeyIdentifier' field.
*/
public static final String SUBJECT_KEY_IDENTIFIER_FIELD = "subjectKeyIdentifier";
private static final int CA_BYTE_SIZE = 20;
private static final int PREFIX_BYTE_SIZE = 4;
@Column
private final byte[] subjectKeyIdentifier;
@Getter
@Column
private String subjectKeyIdString;
/**
* this field is part of the TCG CA specification, but has not yet been found in
* manufacturer-provided CAs, and is therefore not currently parsed.
*/
@Getter
@Column
private final String credentialType = "TCPA Trusted Platform Module Endorsement";
/**
* Construct a new CertificateAuthorityCredential given its binary contents. The given
* certificate should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificateBytes the contents of a certificate file
* @throws IOException if there is a problem extracting information from the certificate
*/
public CertificateAuthorityCredential(final byte[] certificateBytes)
throws IOException {
super(certificateBytes);
byte[] tempBytes = getX509Certificate()
.getExtensionValue(SUBJECT_KEY_IDENTIFIER_EXTENSION);
if (tempBytes != null && tempBytes.length > CA_BYTE_SIZE) {
this.subjectKeyIdentifier = truncatePrefixBytes(tempBytes);
} else {
this.subjectKeyIdentifier =
getX509Certificate().getExtensionValue(SUBJECT_KEY_IDENTIFIER_EXTENSION);
}
if (this.subjectKeyIdentifier != null) {
this.subjectKeyIdString = Hex.encodeHexString(this.subjectKeyIdentifier);
}
}
/**
* Construct a new CertificateAuthorityCredential by parsing the file at the given path.
* The given certificate should represent either an X509 certificate or X509 attribute
* certificate.
*
* @param certificatePath the path on disk to a certificate
* @throws IOException if there is a problem reading the file
*/
public CertificateAuthorityCredential(final Path certificatePath)
throws IOException {
super(certificatePath);
byte[] tempBytes = getX509Certificate()
.getExtensionValue(SUBJECT_KEY_IDENTIFIER_EXTENSION);
if (tempBytes.length > CA_BYTE_SIZE) {
this.subjectKeyIdentifier = truncatePrefixBytes(tempBytes);
} else {
this.subjectKeyIdentifier =
getX509Certificate().getExtensionValue(SUBJECT_KEY_IDENTIFIER_EXTENSION);
}
if (this.subjectKeyIdentifier != null) {
this.subjectKeyIdString = Hex.encodeHexString(this.subjectKeyIdentifier);
}
}
/**
* Default constructor for Hibernate.
*/
protected CertificateAuthorityCredential() {
subjectKeyIdentifier = null;
}
/**
* @return this certificate's subject key identifier.
*/
public byte[] getSubjectKeyIdentifier() {
if (subjectKeyIdentifier != null) {
return subjectKeyIdentifier.clone();
}
return null;
}
private byte[] truncatePrefixBytes(final byte[] certificateBytes) {
byte[] temp = new byte[CA_BYTE_SIZE];
System.arraycopy(certificateBytes, PREFIX_BYTE_SIZE, temp, 0, CA_BYTE_SIZE);
return temp;
}
@Override
@SuppressWarnings("checkstyle:avoidinlineconditionals")
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
CertificateAuthorityCredential that = (CertificateAuthorityCredential) o;
// if (!Objects.equals(credentialType, that.credentialType)) {
// return false;
// }
return Arrays.equals(subjectKeyIdentifier, that.subjectKeyIdentifier);
}
@Override
@SuppressWarnings({"checkstyle:magicnumber", "checkstyle:avoidinlineconditionals"})
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (credentialType != null ? credentialType.hashCode() : 0);
result = 31 * result + Arrays.hashCode(subjectKeyIdentifier);
return result;
}
}

View File

@ -0,0 +1,47 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
public class CertificateVariables {
public static final String PEM_HEADER = "-----BEGIN CERTIFICATE-----";
public static final String PEM_FOOTER = "-----END CERTIFICATE-----";
public static final String PEM_ATTRIBUTE_HEADER = "-----BEGIN ATTRIBUTE CERTIFICATE-----";
public static final String PEM_ATTRIBUTE_FOOTER = "-----END ATTRIBUTE CERTIFICATE-----";
public static final String MALFORMED_CERT_MESSAGE = "Malformed certificate detected.";
public static final int MAX_CERT_LENGTH_BYTES = 2048;
public static final int MAX_NUMERIC_PRECISION = 49; // Can store up to 160 bit values
public static final int MAX_PUB_KEY_MODULUS_HEX_LENGTH = 1024;
public static final int KEY_USAGE_BIT0 = 0;
public static final int KEY_USAGE_BIT1 = 1;
public static final int KEY_USAGE_BIT2 = 2;
public static final int KEY_USAGE_BIT3 = 3;
public static final int KEY_USAGE_BIT4 = 4;
public static final int KEY_USAGE_BIT5 = 5;
public static final int KEY_USAGE_BIT6 = 6;
public static final int KEY_USAGE_BIT7 = 7;
public static final int KEY_USAGE_BIT8 = 8;
public static final String KEY_USAGE_DS = "DIGITAL SIGNATURE";
public static final String KEY_USAGE_NR = "NON-REPUDIATION";
public static final String KEY_USAGE_KE = "KEY ENCIPHERMENT";
public static final String KEY_USAGE_DE = "DATA ENCIPHERMENT";
public static final String KEY_USAGE_KA = "KEY AGREEMENT";
public static final String KEY_USAGE_KC = "KEY CERT SIGN";
public static final String KEY_USAGE_CS = "CRL SIGN";
public static final String KEY_USAGE_EO = "ENCIPHER ONLY";
public static final String KEY_USAGE_DO = "DECIPHER ONLY";
public static final String ECDSA_OID = "1.2.840.10045.4.3.2";
public static final String ECDSA_SHA224_OID = "1.2.840.10045.4.1";
public static final String RSA256_OID = "1.2.840.113549.1.1.11";
public static final String RSA384_OID = "1.2.840.113549.1.1.12";
public static final String RSA512_OID = "1.2.840.113549.1.1.13";
public static final String RSA224_OID = "1.2.840.113549.1.1.14";
public static final String RSA512_224_OID = "1.2.840.113549.1.1.15";
public static final String RSA512_256_OID = "1.2.840.113549.1.1.16";
public static final String RSA256_STRING = "SHA256WithRSA";
public static final String RSA384_STRING = "SHA384WithRSA";
public static final String RSA224_STRING = "SHA224WithRSA";
public static final String RSA512_STRING = "SHA512WithRSA";
public static final String RSA512_224_STRING = "SHA512-224WithRSA";
public static final String RSA512_256_STRING = "SHA512-256WithRSA";
public static final String ECDSA_STRING = "SHA256WithECDSA";
public static final String ECDSA_SHA224_STRING = "SHA224WithECDSA";
}

View File

@ -0,0 +1,65 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import jakarta.persistence.Entity;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.nio.file.Path;
/**
* This class persists Conformance credentials by extending the base Certificate
* class with fields unique to Conformance credentials.
*/
@NoArgsConstructor(access= AccessLevel.PROTECTED)
@Entity
public class ConformanceCredential extends Certificate {
/**
* This class enables the retrieval of ConformanceCredentials by their attributes.
*/
// public static class Selector extends CertificateSelector<ConformanceCredential> {
// /**
// * Construct a new CertificateSelector that will use the given {@link CertificateManager} to
// * retrieve one or many ConformanceCredentials.
// *
// * @param certificateManager the certificate manager to be used to retrieve certificates
// */
// public Selector(final CertificateManager certificateManager) {
// super(certificateManager, ConformanceCredential.class);
// }
// }
/**
* Get a Selector for use in retrieving ConformanceCredentials.
*
* @param certMan the CertificateManager to be used to retrieve persisted certificates
* @return a ConformanceCredential.Selector instance to use for retrieving certificates
*/
// public static Selector select(final CertificateManager certMan) {
// return new Selector(certMan);
// }
/**
* Construct a new ConformanceCredential given its binary contents. The given certificate
* should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificateBytes the contents of a certificate file
* @throws IOException if there is a problem extracting information from the certificate
*/
public ConformanceCredential(final byte[] certificateBytes) throws IOException {
super(certificateBytes);
}
/**
* Construct a new ConformanceCredential by parsing the file at the given path. The given
* certificate should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificatePath the path on disk to a certificate
* @throws IOException if there is a problem reading the file
*/
public ConformanceCredential(final Path certificatePath) throws IOException {
super(certificatePath);
}
}

View File

@ -0,0 +1,69 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.Device;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MappedSuperclass;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.IOException;
import java.nio.file.Path;
/**
* A Certificate that is associated with a single device.
*
* @see Certificate
*/
@NoArgsConstructor(access= AccessLevel.PACKAGE)
@MappedSuperclass
public abstract class DeviceAssociatedCertificate extends Certificate {
// a device can have multiple certs of this type.
@Getter
@Setter
@ManyToOne
@JoinColumn(name = "device_id")
private Device device;
/**
* Holds the name of the entity 'DEVICE_ID' field.
*/
protected static final String DEVICE_ID_FIELD = "device.id";
/**
* Construct a new Certificate by parsing the file at the given path. The given certificate
* should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificatePath the path on disk to a certificate
* @throws IOException if there is a problem reading the file
*/
DeviceAssociatedCertificate(final Path certificatePath) throws IOException {
super(certificatePath);
}
/**
* Construct a new Certificate given its binary contents. The given certificate should
* represent either an X509 certificate or X509 attribute certificate.
*
* @param certificateBytes the contents of a certificate file
* @throws IOException if there is a problem extracting information from the certificate
*/
DeviceAssociatedCertificate(final byte[] certificateBytes) throws IOException {
super(certificateBytes);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
if (device != null) {
sb.append(String.format("%nDevice -> %s", getDevice().toString()));
}
return sb.toString();
}
}

View File

@ -0,0 +1,652 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TPMSecurityAssertions;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TPMSpecification;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Transient;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.asn1.ASN1ApplicationSpecific;
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Null;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.ASN1UTCTime;
import org.bouncycastle.asn1.DERBMPString;
import org.bouncycastle.asn1.DERExternal;
import org.bouncycastle.asn1.DERGeneralString;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERNumericString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERT61String;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.DERUniversalString;
import org.bouncycastle.asn1.DERVisibleString;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Path;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
*
* This class persists Certificate Authority credentials by extending the base Certificate
* class with fields unique to Endorsement credentials, as defined in the Trusted
* Computing Group Credential Profiles, specification v.1.2.
*
* trustedcomputinggroup.org/wp-content/uploads/Credential_Profiles_V1.2_Level2_Revision8.pdf
*/
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor(access= AccessLevel.PROTECTED)
@Entity
public class EndorsementCredential extends DeviceAssociatedCertificate {
// Indices for ASN1 OBJ items needed for parsing information
private static final int ASN1_OBJ_ID = 0;
private static final int ASN1_OBJ_PRIMITIVE = 1;
private static final int ASN1_FAMILY_INDEX = 0;
private static final int ASN1_LEVEL_INDEX = 1;
private static final int ASN1_REV_INDEX = 2;
private static final int ASN1_VER_INDEX = 0;
private static final int ASN1_UPGRADEABLE_INDEX = 1;
private static final int EK_LOC_VAL_MIN = 0;
private static final int EK_LOC_VAL_MAX = 2;
private static final int EK_TYPE_VAL_MIN = 0;
private static final int EK_TYPE_VAL_MAX = 3;
// EK Tag index values
private static final int EK_TYPE_TAG = 0;
private static final int EK_LOC_TAG = 1;
private static final int EK_CERT_LOC_TAG = 2;
private static final int ASN1_SEQ_UNKNOWN_SIZE = 2;
private static final int ASN1_SEQ_KNOWN_SIZE = 3;
private static final String TPM_MODEL = "2.23.133.2.2";
private static final String TPM_VERSION = "2.23.133.2.3";
private static final String TPM_MANUFACTURER = "2.23.133.2.1";
private static final String TPM_SPECIFICATION = "2.23.133.2.16";
private static final String TPM_SECURITY_ASSERTIONS = "2.23.133.2.18";
private static final String CREDENTIAL_TYPE_LABEL = "1.3.6.1.5.5.7.2.2";
// number of extra bytes potentially present in a cert header.
private static final int EK_CERT_HEADER_BYTE_COUNT = 7;
private static final Logger LOG = LogManager.getLogger(EndorsementCredential.class);
/**
* This class enables the retrieval of EndorsementCredential by their attributes.
*/
// public static class Selector extends CertificateSelector<EndorsementCredential> {
// /**
// * Construct a new CertificateSelector that will use the given {@link CertificateManager} to
// * retrieve one or many EndorsementCredentials.
// *
// * @param certificateManager the certificate manager to be used to retrieve certificates
// */
// public Selector(final CertificateManager certificateManager) {
// super(certificateManager, EndorsementCredential.class);
// }
//
// /**
// * Specify a manufacturer that certificates must have to be considered as matching.
// * @param manufacturer the manufacturer to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byManufacturer(final String manufacturer) {
// setFieldValue(MANUFACTURER_FIELD, manufacturer);
// return this;
// }
//
// /**
// * Specify a model that certificates must have to be considered as matching.
// * @param model the model to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byModel(final String model) {
// setFieldValue(MODEL_FIELD, model);
// return this;
// }
//
// /**
// * Specify a version that certificates must have to be considered as matching.
// * @param version the version to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byVersion(final String version) {
// setFieldValue(VERSION_FIELD, version);
// return this;
// }
//
// /**
// * Specify a device id that certificates must have to be considered
// * as matching.
// *
// * @param device the device id to query
// * @return this instance (for chaining further calls)
// */
// public Selector byDeviceId(final UUID device) {
// setFieldValue(DEVICE_ID_FIELD, device);
// return this;
// }
// }
//
// /**
// * Get a Selector for use in retrieving EndorsementCredentials.
// *
// * @param certMan the CertificateManager to be used to retrieve persisted certificates
// * @return a EndorsementCredential.Selector instance to use for retrieving certificates
// */
// public static Selector select(final CertificateManager certMan) {
// return new Selector(certMan);
// }
/**
* this field is part of the TCG EC specification, but has not yet been found in
* manufacturer-provided ECs, and is therefore not currently parsed
*/
@Getter
@Column
private String credentialType = "TCPA Trusted Platform Module Endorsement";
private static final String MANUFACTURER_FIELD = "manufacturer";
@Getter
@Column
private String manufacturer = null;
private static final String MODEL_FIELD = "model";
@Getter
@Column
private String model = null;
private static final String VERSION_FIELD = "version";
@Getter
@Column
private String version = null;
@Getter
@Embedded
private TPMSpecification tpmSpecification = null;
@Getter
@Embedded
private TPMSecurityAssertions tpmSecurityAssertions = null; //optional
/*
* this field is part of the TCG EC specification, but has not yet been found in
* manufacturer-provided ECs, and is therefore not currently parsed
*/
@Getter
@Column(nullable = true)
private String policyReference = null; // optional
/*
* this field is part of the TCG EC specification, but has not yet been found in
* manufacturer-provided ECs, and is therefore not currently parsed
*/
@Getter
@Column(nullable = true)
private String revocationLocator = null; // optional
@Transient
private Set<String> expectedOids;
@Transient
private Map<String, Object> parsedFields;
private static final Logger LOGGER = LogManager.getLogger(EndorsementCredential.class);
/**
* Construct a new EndorsementCredential given its binary contents. The given
* certificate should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificateBytes the contents of a certificate file
* @throws IOException if there is a problem extracting information from the certificate
*/
public EndorsementCredential(final byte[] certificateBytes) throws IOException {
super(certificateBytes);
parseCertificate();
}
/**
* Construct a new EndorsementCredential by parsing the file at the given path. The given
* certificate should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificatePath the path on disk to a certificate
* @throws IOException if there is a problem reading the file
*/
public EndorsementCredential(final Path certificatePath) throws IOException {
this(readBytes(certificatePath));
}
/**
* Parses the bytes as an EK. If parsing fails initially, the optionally present header
* is removed and tried again. The cert header, if present, contains some certificate length
* information which isn't needed for parsing.
* @param certificateBytes the bytes of the EC
* @return the EC if a valid credential, null otherwise
*/
public static EndorsementCredential parseWithPossibleHeader(final byte[] certificateBytes) {
try {
// first, attempt parsing as is
return new EndorsementCredential(certificateBytes);
} catch (Exception e) {
// attempt parsing again after removing extra header bytes.
if (certificateBytes.length <= EK_CERT_HEADER_BYTE_COUNT) {
throw new IllegalArgumentException("EK parsing failed (only one attempt "
+ "possible", e);
}
}
LOG.debug("Attempting parse after removing extra header bytes");
try {
byte[] truncatedBytes = ArrayUtils.subarray(
certificateBytes, EK_CERT_HEADER_BYTE_COUNT,
certificateBytes.length);
return new EndorsementCredential(truncatedBytes);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse EK after multiple attempts", e);
}
}
/**
* Sets up the OID fields for the parser to search for and prepares a
* hashmap field to hold the discovered values. Must be called once before
* an ASN1Primitive can be parsed.
*/
private void prepareParser() {
expectedOids = new HashSet<>();
expectedOids.add(TPM_MODEL);
expectedOids.add(TPM_VERSION);
expectedOids.add(TPM_MANUFACTURER);
expectedOids.add(TPM_SPECIFICATION);
expectedOids.add(TPM_SECURITY_ASSERTIONS);
expectedOids.add(CREDENTIAL_TYPE_LABEL);
parsedFields = new HashMap<>();
}
/**
* Takes the bytes of an X509 certificate and parses them to extract the relevant fields of an
* Endorsement Credential Certificate. This works by making a single pass through all of the
* ASN1Primitives in the certificate and searches for matching OID keys of specific values. If
* matching OID keys are found, their values are encoded in the fields of the current
* EndorsementCredential object.
* @throws IOException the input certificate bytes were not readable into an X509
* certificate format
*/
private void parseCertificate() throws IOException {
prepareParser();
// although we start with a byte representation, we need to change the encoding to
// make it parseable
ASN1InputStream asn1In = null;
try {
X509Certificate ec = super.getX509Certificate();
asn1In = new ASN1InputStream(ec.getEncoded());
ASN1Primitive obj = asn1In.readObject();
ASN1Sequence seq;
while (obj != null) {
seq = ASN1Sequence.getInstance(obj);
parseSequence(seq, false, null);
obj = asn1In.readObject();
}
} catch (CertificateException e) {
throw new IOException("Couldn't read certificate bytes");
} finally {
if (asn1In != null) {
asn1In.close();
}
}
String oid;
Object value;
// unpack fields from parsedFields and set field values
for (Map.Entry<String, Object> entry : parsedFields.entrySet()) {
oid = entry.getKey();
value = entry.getValue();
if (oid.equals(TPM_MODEL)) {
model = value.toString();
LOGGER.debug("Found TPM Model: " + model);
} else if (oid.equals(TPM_VERSION)) {
version = value.toString();
LOGGER.debug("Found TPM Version: " + version);
} else if (oid.equals(TPM_MANUFACTURER)) {
manufacturer = value.toString();
LOGGER.debug("Found TPM Manufacturer: " + manufacturer);
}
}
}
/**
* Parses the ASN1Sequence type by iteratively unpacking each successive element. If,
* however, the method is set to add the sequence to the OID mapping, it may search for
* patterns that correspond to the TPM Security Assertions and TPM Specification and set
* those fields appropriately.
* @param seq the sequence to parse
* @param addToMapping whether or not to store the sequence value as an OID key/value value
* @param key the associated OID key with this value necessary if addToMapping is true
* @throws IOException parsing individual subcomponents failed
*/
private void parseSequence(final ASN1Sequence seq, final boolean addToMapping,
final String key) throws IOException {
// need to check if an OID/Value pair
// it is possible these pairs could be in a larger sequence of size != 2
// but it appears that all expected TPM related fields are of size 2.
// The other larger ones are only used for generic X509 fields, which we
// don't need to extract here.
if (seq.size() == ASN1_SEQ_UNKNOWN_SIZE) {
ASN1Encodable obj1 = seq.getObjectAt(ASN1_OBJ_ID);
ASN1Encodable obj2 = seq.getObjectAt(ASN1_OBJ_PRIMITIVE);
if (obj1 instanceof ASN1ObjectIdentifier) {
String oid = ((ASN1ObjectIdentifier) obj1).getId();
if (expectedOids.contains(oid)) {
// parse and put object 2
parseSingle((ASN1Primitive) obj2, true, oid);
} else {
// there may be subfields that are expected, so continue parsing
parseSingle((ASN1Primitive) obj2, false, null);
}
}
// The next two are special sequences that have already been matched with an OID.
} else if (addToMapping && key.equals(TPM_SPECIFICATION)
&& seq.size() == ASN1_SEQ_KNOWN_SIZE) {
// Parse TPM Specification
DERUTF8String family = (DERUTF8String) seq.getObjectAt(ASN1_FAMILY_INDEX);
ASN1Integer level = (ASN1Integer) seq.getObjectAt(ASN1_LEVEL_INDEX);
ASN1Integer revision = (ASN1Integer) seq.getObjectAt(ASN1_REV_INDEX);
tpmSpecification = new TPMSpecification(family.getString(), level.getValue(),
revision.getValue());
LOGGER.debug("Found TPM Spec:" + tpmSpecification.toString());
} else if (addToMapping && key.equals(TPM_SECURITY_ASSERTIONS)) {
// Parse TPM Security Assertions
int seqPosition = 0;
ASN1Integer ver;
// Parse Security Assertions Version
if (seq.getObjectAt(seqPosition) instanceof ASN1Integer) {
ver = (ASN1Integer) seq.getObjectAt(seqPosition);
seqPosition++;
} else {
// Default value of 1 if field not found
ver = new ASN1Integer(BigInteger.ONE);
}
ASN1Boolean fieldUpgradeable;
// Parse Security Assertions Field Upgradeable
if (seq.getObjectAt(seqPosition) instanceof ASN1Boolean) {
fieldUpgradeable = (ASN1Boolean) seq.getObjectAt(seqPosition);
seqPosition++;
} else {
// Default value of false if field not found
fieldUpgradeable = ASN1Boolean.getInstance(false);
}
tpmSecurityAssertions = new TPMSecurityAssertions(ver.getValue(),
fieldUpgradeable.isTrue());
LOGGER.debug("Found TPM Assertions: " + tpmSecurityAssertions.toString());
// Iterate through remaining fields to set optional attributes
int tag;
DERTaggedObject obj;
for (int i = seqPosition; i < seq.size(); i++) {
if (seq.getObjectAt(i) instanceof DERTaggedObject) {
obj = (DERTaggedObject) seq.getObjectAt(i);
tag = obj.getTagNo();
if (tag == EK_TYPE_TAG) {
int ekGenTypeVal = ((ASN1Enumerated) obj.getObject()).getValue().intValue();
if (ekGenTypeVal >= EK_TYPE_VAL_MIN && ekGenTypeVal <= EK_TYPE_VAL_MAX) {
TPMSecurityAssertions.EkGenerationType ekGenType
= TPMSecurityAssertions.EkGenerationType.values()[ekGenTypeVal];
tpmSecurityAssertions.setEkGenType(ekGenType);
}
} else if (tag == EK_LOC_TAG) {
int ekGenLocVal = ((ASN1Enumerated) obj.getObject()).getValue().intValue();
if (ekGenLocVal >= EK_LOC_VAL_MIN && ekGenLocVal <= EK_LOC_VAL_MAX) {
TPMSecurityAssertions.EkGenerationLocation ekGenLocation
= TPMSecurityAssertions.EkGenerationLocation.values()[ekGenLocVal];
tpmSecurityAssertions.setEkGenerationLocation(ekGenLocation);
}
} else if (tag == EK_CERT_LOC_TAG) {
int ekCertGenLocVal = ((ASN1Enumerated) obj.getObject())
.getValue().intValue();
if (ekCertGenLocVal >= EK_LOC_VAL_MIN
&& ekCertGenLocVal <= EK_LOC_VAL_MAX) {
TPMSecurityAssertions.EkGenerationLocation ekCertGenLoc
= TPMSecurityAssertions.EkGenerationLocation.
values()[ekCertGenLocVal];
tpmSecurityAssertions.setEkGenerationLocation(ekCertGenLoc);
}
}
// ccInfo, fipsLevel, iso9000Certified, and iso9000Uri still to be implemented
}
// Will need additional else if case in the future for instanceof ASN1Boolean when
// supporting TPMSecurityAssertions iso9000Certified field, which could be either
// DERTaggedObject or ASN1Boolean
}
} else {
//parse the elements of the sequence individually
for (ASN1Encodable component : seq) {
parseSingle((ASN1Primitive) component, false, null);
}
}
}
/**
* Parses the many different types of ASN1Primitives and searches for specific OID
* key/value pairs. Works by traversing the entire ASN1Primitive tree with a single
* pass and populates relevant fields in the EndorsementCredential object.
* @param component the ASN1Primitive to parse
* @param addToMapping whether or not the current component has been matched as the
* value in an expected TPM OID key/value pair
* @param key if addToMapping is true, the key in the OID key/value pair
* @throws IOException parsing of subcomponents in the tree failed.
*/
@SuppressWarnings("checkstyle:methodlength")
private void parseSingle(final ASN1Primitive component, final boolean addToMapping,
final String key) throws IOException {
// null check the key if addToMapping is true
if (addToMapping && StringUtils.isEmpty(key)) {
throw new IllegalArgumentException("Key cannot be empty if adding to field mapping");
}
if (component instanceof ASN1Sequence) {
parseSequence((ASN1Sequence) component, addToMapping, key);
} else if (component instanceof DERUTF8String) {
if (addToMapping) {
DERUTF8String nameData = (DERUTF8String) component;
parsedFields.put(key, nameData.getString());
}
} else if (component instanceof ASN1ObjectIdentifier) {
if (addToMapping) {
// shouldn't ever be reached, but just in case
parsedFields.put(key, ((ASN1ObjectIdentifier) component).getId());
}
} else if (component instanceof ASN1TaggedObject) {
ASN1TaggedObject taggedObj = (ASN1TaggedObject) component;
parseSingle(taggedObj.getObject(), addToMapping, key);
} else if (component instanceof ASN1OctetString) {
// this may contain parseable data or may just be a OID key-pair value
ASN1OctetString octStr = (ASN1OctetString) component;
byte[] bytes = octStr.getOctets();
ByteArrayInputStream inStream = new ByteArrayInputStream(bytes);
ASN1InputStream octIn = new ASN1InputStream(inStream);
try {
ASN1Encodable newComp = octIn.readObject();
parseSingle((ASN1Primitive) newComp, false, null);
} catch (IOException e) {
// this means octet string didn't contain parsable data, so store the
// value as is
if (addToMapping) {
parsedFields.put(key, bytes);
}
} finally {
if (octIn != null) {
octIn.close();
}
}
} else if (component instanceof ASN1Set) {
// all ECs seen to this point use sets differently than sequences and their sets
// don't contain top level OIDs, so we can parse everything term by term, if that
// ceases to be the case, we need to switch to this parsing to be more like
// parseSequences in the future
ASN1Set set = (ASN1Set) component;
Enumeration setContents = set.getObjects();
ASN1Encodable subComp;
while (setContents.hasMoreElements()) {
subComp = (ASN1Encodable) setContents.nextElement();
if (subComp instanceof ASN1ObjectIdentifier) {
LOGGER.warn("OID in top level of ASN1Set");
}
parseSingle((ASN1Primitive) subComp, addToMapping, key);
}
} else if (component instanceof ASN1Boolean) {
if (addToMapping) {
boolean fieldVal = ((ASN1Boolean) component).isTrue();
parsedFields.put(key, fieldVal);
}
} else if (component instanceof ASN1BitString) {
// I don't think this contains more fields and needs to be reparsed,
// though not 100% sure
if (addToMapping) {
byte[] bytes = ((ASN1BitString) component).getBytes();
parsedFields.put(key, bytes);
}
} else if (component instanceof ASN1Integer) {
if (addToMapping) {
BigInteger bigInt = ((ASN1Integer) component).getValue();
parsedFields.put(key, bigInt);
}
} else if (component instanceof ASN1Null) {
if (addToMapping) {
parsedFields.put(key, null);
}
} else if (component instanceof ASN1UTCTime) {
if (addToMapping) {
try {
parsedFields.put(key, ((ASN1UTCTime) component).getDate());
} catch (ParseException pe) {
pe.printStackTrace();
}
}
} else if (component instanceof DERPrintableString) {
if (addToMapping) {
parsedFields.put(key, ((DERPrintableString) component).getString());
}
} else if (component instanceof ASN1Enumerated) {
if (addToMapping) {
BigInteger value = ((ASN1Enumerated) component).getValue();
parsedFields.put(key, value);
}
// after about this point, I doubt we'll see any of the following field types, but
// in the interest of completeness and robustness, they are still parsed
} else if (component instanceof DERIA5String) {
if (addToMapping) {
String ia5Str = ((DERIA5String) component).getString();
parsedFields.put(key, ia5Str);
}
} else if (component instanceof DERNumericString) {
if (addToMapping) {
String numStr = ((DERNumericString) component).getString();
parsedFields.put(key, numStr);
}
} else if (component instanceof ASN1GeneralizedTime) {
if (addToMapping) {
try {
parsedFields.put(key, ((ASN1GeneralizedTime) component).getDate());
} catch (ParseException e) {
e.printStackTrace();
}
}
} else if (component instanceof ASN1ApplicationSpecific) {
parseSingle(((ASN1ApplicationSpecific) component).getObject(), addToMapping, key);
} else if (component instanceof DERBMPString) {
if (addToMapping) {
String bmpStr = ((DERBMPString) component).getString();
parsedFields.put(key, bmpStr);
}
} else if (component instanceof DERExternal) {
parseSingle(((DERExternal) component).getExternalContent(), addToMapping, key);
} else if (component instanceof DERGeneralString) {
if (addToMapping) {
String generalStr = ((DERGeneralString) component).getString();
parsedFields.put(key, generalStr);
}
} else if (component instanceof DERT61String) {
if (addToMapping) {
String t61Str = ((DERT61String) component).getString();
parsedFields.put(key, t61Str);
}
} else if (component instanceof DERUniversalString) {
if (addToMapping) {
String univStr = ((DERUniversalString) component).getString();
parsedFields.put(key, univStr);
}
} else if (component instanceof DERVisibleString) {
if (addToMapping) {
String visStr = ((DERVisibleString) component).getString();
parsedFields.put(key, visStr);
}
} else {
// there are some deprecated types that we don't parse
LOGGER.error("Unparsed type: " + component.getClass());
}
}
}

View File

@ -0,0 +1,105 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Set;
/**
* Represents an issued attestation certificate to a HIRS Client.
*/
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class IssuedAttestationCertificate extends DeviceAssociatedCertificate {
/**
* AIC label that must be used.
*/
public static final String AIC_TYPE_LABEL = "TCPA Trusted Platform Identity";
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "ek_id")
private EndorsementCredential endorsementCredential;
@ManyToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "pc_id")
private Set<PlatformCredential> platformCredentials;
/**
* This class enables the retrieval of IssuedAttestationCertificate by their attributes.
*/
// public static class Selector extends CertificateSelector<IssuedAttestationCertificate> {
// /**
// * Construct a new CertificateSelector that will use the given {@link CertificateManager} to
// * retrieve one or many IssuedAttestationCertificate.
// *
// * @param certificateManager the certificate manager to be used to retrieve certificates
// */
// public Selector(final CertificateManager certificateManager) {
// super(certificateManager, IssuedAttestationCertificate.class);
// }
//
// /**
// * Specify a device id that certificates must have to be considered
// * as matching.
// *
// * @param device the device id to query
// * @return this instance (for chaining further calls)
// */
// public Selector byDeviceId(final UUID device) {
// setFieldValue(DEVICE_ID_FIELD, device);
// return this;
// }
// }
//
// /**
// * Get a Selector for use in retrieving IssuedAttestationCertificate.
// *
// * @param certMan the CertificateManager to be used to retrieve persisted certificates
// * @return a IssuedAttestationCertificate.Selector instance to use for retrieving certificates
// */
// public static IssuedAttestationCertificate.Selector select(final CertificateManager certMan) {
// return new IssuedAttestationCertificate.Selector(certMan);
// }
/**
* Constructor.
* @param certificateBytes the issued certificate bytes
* @param endorsementCredential the endorsement credential
* @param platformCredentials the platform credentials
* @throws IOException if there is a problem extracting information from the certificate
*/
public IssuedAttestationCertificate(final byte[] certificateBytes,
final EndorsementCredential endorsementCredential,
final Set<PlatformCredential> platformCredentials)
throws IOException {
super(certificateBytes);
this.endorsementCredential = endorsementCredential;
this.platformCredentials = platformCredentials;
}
/**
* Constructor.
* @param certificatePath path to certificate
* @param endorsementCredential the endorsement credential
* @param platformCredentials the platform credentials
* @throws IOException if there is a problem extracting information from the certificate
*/
public IssuedAttestationCertificate(final Path certificatePath,
final EndorsementCredential endorsementCredential,
final Set<PlatformCredential> platformCredentials)
throws IOException {
this(readBytes(certificatePath), endorsementCredential, platformCredentials);
}
}

View File

@ -0,0 +1,796 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import com.google.common.base.Preconditions;
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.PlatformConfigurationV1;
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.V2.PlatformConfigurationV2;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Transient;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.util.Strings;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Attribute;
import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.PolicyQualifierInfo;
import org.bouncycastle.asn1.x509.UserNotice;
import org.bouncycastle.operator.ContentVerifier;
import org.bouncycastle.operator.ContentVerifierProvider;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class persists Platform credentials by extending the base Certificate
* class with fields unique to a Platform credentials, as defined in the Trusted
* Computing Group Credential Profiles, specification v.1.2.
*/
@Getter
@Setter
@Log4j2
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class PlatformCredential extends DeviceAssociatedCertificate {
private static final int TCG_SPECIFICATION_LENGTH = 3;
// These are Object Identifiers (OIDs) for sections in the credentials
private static final String POLICY_QUALIFIER_CPSURI = "1.3.6.1.5.5.7.2.1";
private static final String POLICY_QUALIFIER_USER_NOTICE = "1.3.6.1.5.5.7.2.2";
// OID for TCG Attributes
private static final String PLATFORM_MANUFACTURER = "2.23.133.2.4";
private static final String PLATFORM_MODEL = "2.23.133.2.5";
private static final String PLATFORM_VERSION = "2.23.133.2.6";
private static final String PLATFORM_SERIAL = "2.23.133.2.23";
private static final String PLATFORM_BASEBOARD_CHASSIS_COMBINED = "2.23.133.5.1.6";
// OID for TCG Platform Class Common Attributes
private static final String PLATFORM_MANUFACTURER_2_0 = "2.23.133.5.1.1";
private static final String PLATFORM_MODEL_2_0 = "2.23.133.5.1.4";
private static final String PLATFORM_VERSION_2_0 = "2.23.133.5.1.5";
private static final String PLATFORM_SERIAL_2_0 = "2.23.133.5.1.6";
// OID for Certificate Attributes
private static final String TCG_PLATFORM_SPECIFICATION = "2.23.133.2.17";
private static final String TPM_SECURITY_ASSERTION = "2.23.133.2.18";
private static final String TBB_SECURITY_ASSERTION = "2.23.133.2.19";
private static final String TCG_CREDENTIAL_SPECIFICATION = "2.23.133.2.23";
private static final String PLATFORM_CONFIGURATION_URI = "2.23.133.5.1.3";
private static final String PLATFORM_CONFIGURATION = "2.23.133.5.1.7.1";
private static final String PLATFORM_CONFIGURATION_V2 = "2.23.133.5.1.7.2";
private static final String PLATFORM_CREDENTIAL_TYPE = "2.23.133.2.25";
private static final String PLATFORM_BASE_CERT = "2.23.133.8.2";
private static final String PLATFORM_DELTA_CERT = "2.23.133.8.5";
/**
* TCG Platform Specification values
* At this time these are placeholder values.
*/
private static final Map<String, String> TCG_PLATFORM_MAP = new HashMap<String, String>() {{
put("#00000000", "Unclassified");
put("#00000001", "PC Client");
put("#00000002", "PDA");
put("#00000003", "CELLPHONE");
put("#00000004", "SERVER");
put("#00000005", "PERIPHERAL");
put("#00000006", "TSS");
put("#00000007", "STORAGE");
put("#00000008", "AUTHENTICATION");
put("#00000009", "EMBEDDED");
put("#00000010", "HARD COPY");
put("#00000011", "INFRASTRUCTURE");
put("#00000012", "VIRTUALIZATION");
put("#00000013", "TNC");
put("#00000014", "MULTI-TENANT");
}};
// number of extra bytes potentially present in a cert header.
private static final int PC_CERT_HEADER_BYTE_COUNT = 8;
/**
* TCPA Trusted Platform Endorsement.
*/
public static final String CERTIFICATE_TYPE_1_2 = "TCPA Trusted Platform Endorsement";
/**
* TCG Trusted Platform Endorsement.
*/
public static final String CERTIFICATE_TYPE_2_0 = "TCG Trusted Platform Endorsement";
/**
* This class enables the retrieval of PlatformCredentials by their attributes.
*/
// public static class Selector extends CertificateSelector<PlatformCredential> {
// /**
// * Construct a new CertificateSelector that will use the given {@link CertificateManager} to
// * retrieve one or many PlatformCredentials.
// *
// * @param certificateManager the certificate manager to be used to retrieve certificates
// */
// public Selector(final CertificateManager certificateManager) {
// super(certificateManager, PlatformCredential.class);
// }
//
// /**
// * Specify a manufacturer that certificates must have to be considered as matching.
// * @param manufacturer the manufacturer to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byManufacturer(final String manufacturer) {
// setFieldValue(MANUFACTURER_FIELD, manufacturer);
// return this;
// }
//
// /**
// * Specify a model that certificates must have to be considered as matching.
// * @param model the model to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byModel(final String model) {
// setFieldValue(MODEL_FIELD, model);
// return this;
// }
//
// /**
// * Specify a version that certificates must have to be considered as matching.
// * @param version the version to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byVersion(final String version) {
// setFieldValue(VERSION_FIELD, version);
// return this;
// }
//
// /**
// * Specify a serial number that certificates must have to be considered as matching.
// * @param serialNumber the serial number to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector bySerialNumber(final String serialNumber) {
// setFieldValue(SERIAL_NUMBER_FIELD, serialNumber);
// return this;
// }
//
// /**
// * Specify a board serial number that certificates must have to be considered as matching.
// * @param boardSerialNumber the board serial number to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byBoardSerialNumber(final String boardSerialNumber) {
// setFieldValue(PLATFORM_SERIAL_FIELD, boardSerialNumber);
// return this;
// }
//
// /**
// * Specify a chassis serial number that certificates must have to be considered as matching.
// * @param chassisSerialNumber the board serial number to query, not empty or null
// * @return this instance (for chaining further calls)
// */
// public Selector byChassisSerialNumber(final String chassisSerialNumber) {
// setFieldValue(CHASSIS_SERIAL_NUMBER_FIELD, chassisSerialNumber);
// return this;
// }
//
// /**
// * Specify a device id that certificates must have to be considered
// * as matching.
// *
// * @param device the device id to query
// * @return this instance (for chaining further calls)
// */
// public Selector byDeviceId(final UUID device) {
// setFieldValue(DEVICE_ID_FIELD, device);
// return this;
// }
// }
@Column
private String credentialType = null;
@Column
private boolean platformBase = false;
private static final String MANUFACTURER_FIELD = "manufacturer";
@Column
private String manufacturer = null;
private static final String MODEL_FIELD = "model";
@Column
private String model = null;
private static final String VERSION_FIELD = "version";
@Column
private String version = null;
private static final String PLATFORM_SERIAL_FIELD = "platformSerial";
@Column
private String platformSerial = null;
private static final String CHASSIS_SERIAL_NUMBER_FIELD = "chassisSerialNumber";
@Column
private String chassisSerialNumber;
@Column
private int majorVersion = 0;
@Column
private int minorVersion = 0;
@Column
private int revisionLevel = 0;
@Column
private int tcgCredentialMajorVersion = 0;
@Column
private int tcgCredentialMinorVersion = 0;
@Column
private int tcgCredentialRevisionLevel = 0;
@Column
private String platformClass = null;
@Column(length = MAX_MESSAGE_LENGTH)
private String componentFailures = Strings.EMPTY;
@Transient
private EndorsementCredential endorsementCredential = null;
private String platformChainType = Strings.EMPTY;
private boolean isDeltaChain = false;
/**
* Get a Selector for use in retrieving PlatformCredentials.
*
* @param certMan the CertificateManager to be used to retrieve persisted certificates
* @return a PlatformCredential.Selector instance to use for retrieving certificates
*/
// public static Selector select(final CertificateManager certMan) {
// return new Selector(certMan);
// }
/**
* Construct a new PlatformCredential given its binary contents. ParseFields is
* optionally run. The given certificate should represent either an X509 certificate
* or X509 attribute certificate.
*
* @param certificateBytes the contents of a certificate file
* @param parseFields boolean True to parse fields
* @throws IOException if there is a problem extracting information from the certificate\
*/
public PlatformCredential(final byte[] certificateBytes,
final boolean parseFields) throws IOException {
super(certificateBytes);
if (parseFields) {
parseFields();
}
}
/**
* Construct a new PlatformCredential given its binary contents. The given
* certificate should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificateBytes the contents of a certificate file
* @throws IOException if there is a problem extracting information from the certificate
*/
public PlatformCredential(final byte[] certificateBytes) throws IOException {
this(certificateBytes, true);
}
/**
* Construct a new PlatformCredential by parsing the file at the given path. The given
* certificate should represent either an X509 certificate or X509 attribute certificate.
*
* @param certificatePath the path on disk to a certificate
* @throws IOException if there is a problem reading the file
*/
public PlatformCredential(final Path certificatePath) throws IOException {
this(readBytes(certificatePath), true);
}
/**
* Validate the signature on the attribute certificate in this holder.
*
* @param verifierProvider a ContentVerifierProvider that can generate a
* verifier for the signature.
* @return true if the signature is valid, false otherwise.
* @throws IOException if the signature cannot be processed or is inappropriate.
*/
public boolean isSignatureValid(final ContentVerifierProvider verifierProvider)
throws IOException {
AttributeCertificate attCert = getAttributeCertificate();
AttributeCertificateInfo acinfo = getAttributeCertificate().getAcinfo();
// Check if the algorithm identifier is the same
if (!isAlgIdEqual(acinfo.getSignature(), attCert.getSignatureAlgorithm())) {
throw new IOException("signature invalid - algorithm identifier mismatch");
}
ContentVerifier verifier;
try {
// Set ContentVerifier with the signature that will verify
verifier = verifierProvider.get((acinfo.getSignature()));
} catch (Exception e) {
throw new IOException("unable to process signature: " + e.getMessage(), e);
}
return verifier.verify(attCert.getSignatureValue().getOctets());
}
/**
* Parses the bytes as an PC. If parsing fails initially, the optionally present header
* is removed and tried again. The cert header, if present, contains some certificate length
* information which isn't needed for parsing.
* @param certificateBytes the bytes of the PC
* @return the PC if a valid credential, null otherwise
*/
public static PlatformCredential parseWithPossibleHeader(final byte[] certificateBytes) {
PlatformCredential credential = null;
try {
// first, attempt parsing as is
credential = new PlatformCredential(certificateBytes);
} catch (Exception e) {
// attempt parsing again after removing extra header bytes.
if (certificateBytes.length > PC_CERT_HEADER_BYTE_COUNT) {
log.debug("Attempting parse after removing extra header bytes");
try {
byte[] truncatedBytes = ArrayUtils.subarray(
certificateBytes, PC_CERT_HEADER_BYTE_COUNT,
certificateBytes.length);
credential = new PlatformCredential(truncatedBytes);
} catch (Exception e1) {
log.warn("Failed to parse PC after multiple attempts", e1);
}
} else {
log.warn("EK parsing failed (only one attempt possible)", e);
}
}
return credential;
}
private void parseFields() throws IOException {
AttributeCertificateInfo certificate = getAttributeCertificate().getAcinfo();
Map<String, String> policyQualifier = getPolicyQualifier(certificate);
credentialType = policyQualifier.get("userNotice");
// Parse data based on certificate type (1.2 vs 2.0)
switch (credentialType) {
case CERTIFICATE_TYPE_1_2:
parseAttributeCert(certificate);
break;
case CERTIFICATE_TYPE_2_0:
parseAttributeCert2(certificate);
break;
default:
throw new IOException("Invalid Attribute Credential Type: " + credentialType);
}
// Get TCG Platform Specification Information
for (ASN1Encodable enc : certificate.getAttributes().toArray()) {
Attribute attr = Attribute.getInstance(enc);
if (attr.getAttrType().toString().equals(TCG_PLATFORM_SPECIFICATION)) {
ASN1Sequence tcgPlatformSpecification
= ASN1Sequence.getInstance(attr.getAttrValues().getObjectAt(0));
ASN1Sequence tcgSpecificationVersion
= ASN1Sequence.getInstance(tcgPlatformSpecification.getObjectAt(0));
this.majorVersion = Integer.parseInt(
tcgSpecificationVersion.getObjectAt(0).toString());
this.minorVersion = Integer.parseInt(
tcgSpecificationVersion.getObjectAt(1).toString());
this.revisionLevel = Integer.parseInt(
tcgSpecificationVersion.getObjectAt(2).toString());
this.platformClass = tcgPlatformSpecification.getObjectAt(1).toString();
} else if (attr.getAttrType().toString().equals(PLATFORM_CREDENTIAL_TYPE)) {
ASN1Sequence tcgPlatformType = ASN1Sequence.getInstance(
attr.getAttrValues().getObjectAt(0));
ASN1ObjectIdentifier platformOid = ASN1ObjectIdentifier.getInstance(
tcgPlatformType.getObjectAt(0));
if (platformOid.getId().equals(PLATFORM_BASE_CERT)) {
this.platformBase = true;
this.platformChainType = "Base";
this.isDeltaChain = true;
} else if (platformOid.getId().equals(PLATFORM_DELTA_CERT)) {
this.platformBase = false;
this.platformChainType = "Delta";
this.isDeltaChain = true;
}
}
}
}
/**
* Parse a 1.2 Platform Certificate (Attribute Certificate).
* @param certificate Attribute Certificate
*/
private void parseAttributeCert(final AttributeCertificateInfo certificate) {
Extension subjectAlternativeNameExtension
= certificate.getExtensions().getExtension(Extension.subjectAlternativeName);
// It contains a Subject Alternative Name Extension
if (subjectAlternativeNameExtension != null) {
GeneralNames gnames = GeneralNames.getInstance(
subjectAlternativeNameExtension.getParsedValue());
for (GeneralName gname : gnames.getNames()) {
// Check if it's a directoryName [4] Name type
if (gname.getTagNo() == GeneralName.directoryName) {
X500Name name = X500Name.getInstance(gname.getName());
for (RDN rdn: name.getRDNs()) {
for (AttributeTypeAndValue attTV: rdn.getTypesAndValues()) {
switch (attTV.getType().toString()) {
case PLATFORM_MANUFACTURER:
this.manufacturer = attTV.getValue().toString();
break;
case PLATFORM_MODEL:
this.model = attTV.getValue().toString();
break;
case PLATFORM_VERSION:
this.version = attTV.getValue().toString();
break;
case PLATFORM_SERIAL:
this.platformSerial = attTV.getValue().toString();
break;
case PLATFORM_BASEBOARD_CHASSIS_COMBINED:
String[] combinedValues = attTV.getValue()
.toString()
.split(",");
if (combinedValues.length != 2) {
log.warn("Unable to parse combined "
+ "baseboard/chassis SN field");
} else {
this.chassisSerialNumber = combinedValues[0];
this.platformSerial = combinedValues[1];
}
break;
default:
break;
}
}
}
}
}
}
}
/**
* Parse a 2.0 Platform Certificate (Attribute Certificate).
* @param certificate Attribute Certificate
*/
private void parseAttributeCert2(final AttributeCertificateInfo certificate)
throws IOException {
Extension subjectAlternativeNameExtension
= certificate.getExtensions().getExtension(Extension.subjectAlternativeName);
// It contains a Subject Alternative Name Extension
if (subjectAlternativeNameExtension != null) {
GeneralNames gnames = GeneralNames.getInstance(
subjectAlternativeNameExtension.getParsedValue());
for (GeneralName gname : gnames.getNames()) {
// Check if it's a directoryName [4] Name type
if (gname.getTagNo() == GeneralName.directoryName) {
X500Name name = X500Name.getInstance(gname.getName());
for (RDN rdn: name.getRDNs()) {
for (AttributeTypeAndValue attTV: rdn.getTypesAndValues()) {
switch (attTV.getType().toString()) {
case PLATFORM_MANUFACTURER_2_0:
this.manufacturer = attTV.getValue().toString();
break;
case PLATFORM_MODEL_2_0:
this.model = attTV.getValue().toString();
break;
case PLATFORM_VERSION_2_0:
this.version = attTV.getValue().toString();
break;
case PLATFORM_SERIAL_2_0:
this.platformSerial = attTV.getValue().toString();
break;
default:
break;
}
}
}
}
}
}
// Get all the attributes map to check for validity
try {
getAllAttributes();
} catch (IllegalArgumentException ex) {
throw new IOException(ex.getMessage());
}
}
/**
* Get the x509 Platform Certificate version.
* @return a big integer representing the certificate version.
*/
@Override
public int getX509CredentialVersion() {
try {
return getAttributeCertificate()
.getAcinfo()
.getVersion()
.getValue().intValue();
} catch (IOException ex) {
log.warn("X509 Credential Version not found.");
log.error(ex);
return Integer.MAX_VALUE;
}
}
/**
* Get the cPSuri from the Certificate Policies.
* @return cPSuri from the CertificatePolicies.
* @throws IOException when reading the certificate.
*/
public String getCPSuri() throws IOException {
Map<String, String> policyQualifier
= getPolicyQualifier(getAttributeCertificate().getAcinfo());
if (policyQualifier.get("cpsURI") != null && !policyQualifier.get("cpsURI").isEmpty()) {
return policyQualifier.get("cpsURI");
}
return null;
}
/**
* Get the Platform Configuration Attribute from the Platform Certificate.
* @return a map with all the attributes
* @throws IllegalArgumentException when there is a parsing error
* @throws IOException when reading the certificate.
*/
public Map<String, Object> getAllAttributes()
throws IllegalArgumentException, IOException {
Map<String, Object> attributes = new HashMap<>();
ASN1Sequence attributeSequence;
// Check all attributes for Platform Configuration
for (ASN1Encodable enc: getAttributeCertificate().getAcinfo().getAttributes().toArray()) {
Attribute attr = Attribute.getInstance(enc);
attributeSequence
= ASN1Sequence.getInstance(attr.getAttrValues().getObjectAt(0));
// Parse sequence based on the attribute OID
switch (attr.getAttrType().getId()) {
case TBB_SECURITY_ASSERTION:
attributes.put("tbbSecurityAssertion",
new TBBSecurityAssertion(attributeSequence));
break;
case PLATFORM_CONFIGURATION_URI:
attributes.put("platformConfigurationURI",
new URIReference(attributeSequence));
break;
case PLATFORM_CONFIGURATION:
attributes.put("platformConfiguration",
new PlatformConfigurationV1(attributeSequence));
break;
case PLATFORM_CONFIGURATION_V2:
attributes.put("platformConfiguration",
new PlatformConfigurationV2(attributeSequence));
break;
case TCG_PLATFORM_SPECIFICATION:
case PLATFORM_CREDENTIAL_TYPE:
// handled in parseFields
break;
case TCG_CREDENTIAL_SPECIFICATION:
getTCGCredentialSpecification(attributeSequence);
break;
default:
// No class defined for this attribute
log.warn("No class defined for attribute with OID: "
+ attr.getAttrType().getId());
break;
}
}
return attributes;
}
/**
* Get the specified attribute from the Platform Certificate.
* @param attributeName to retrieve from the map.
* @return an Object with the attribute.
* @throws IllegalArgumentException when there is a parsing error
* @throws IOException when reading the certificate.
*/
public Object getAttribute(final String attributeName)
throws IllegalArgumentException, IOException {
return getAllAttributes().get(attributeName);
}
/**
* Get the Platform Configuration Attribute from the Platform Certificate.
* @return a map with the Platform Configuration information.
* @throws IllegalArgumentException when there is a parsing error
* @throws IOException when reading the certificate.
*/
public PlatformConfiguration getPlatformConfiguration()
throws IllegalArgumentException, IOException {
if (getAttribute("platformConfiguration") != null
&& getAttribute("platformConfiguration") instanceof PlatformConfiguration) {
return (PlatformConfiguration) getAttribute("platformConfiguration");
}
return null;
}
/**
* Get the Platform Configuration URI Attribute from the Platform Certificate.
* @return an URIReference object to the Platform Configuration URI.
* @throws IllegalArgumentException when there is a parsing error
* @throws IOException when reading the certificate.
*/
public URIReference getPlatformConfigurationURI()
throws IllegalArgumentException, IOException {
if (getAttribute("platformConfigurationURI") != null
&& getAttribute("platformConfigurationURI") instanceof URIReference) {
return (URIReference) getAttribute("platformConfigurationURI");
}
return null;
}
/**
* Get the TBB Security Assertion from the Platform Certificate.
* @return a TBBSecurityAssertion object.
* @throws IllegalArgumentException when there is a parsing error
* @throws IOException when reading the certificate.
*/
public TBBSecurityAssertion getTBBSecurityAssertion()
throws IllegalArgumentException, IOException {
if (getAttribute("tbbSecurityAssertion") != null
&& getAttribute("tbbSecurityAssertion") instanceof TBBSecurityAssertion) {
return (TBBSecurityAssertion) getAttribute("tbbSecurityAssertion");
}
return null;
}
/**
* This method sets the TCG Credential fields from a certificate, if provided.
*
* @param attributeSequence The sequence associated with 2.23.133.2.23
*/
private void getTCGCredentialSpecification(final ASN1Sequence attributeSequence) {
try {
this.tcgCredentialMajorVersion = Integer.parseInt(
attributeSequence.getObjectAt(0).toString());
this.tcgCredentialMinorVersion = Integer.parseInt(
attributeSequence.getObjectAt(1).toString());
this.tcgCredentialRevisionLevel = Integer.parseInt(
attributeSequence.getObjectAt(2).toString());
} catch (NumberFormatException nfEx) {
// ill-formed ASN1
String fieldContents = attributeSequence.toString();
if (fieldContents != null && fieldContents.contains(",")) {
fieldContents = fieldContents.replaceAll("[^a-zA-Z0-9,]", "");
String[] fields = fieldContents.split(",");
if (fields.length == TCG_SPECIFICATION_LENGTH) {
this.tcgCredentialMajorVersion = Integer.parseInt(fields[0]);
this.tcgCredentialMinorVersion = Integer.parseInt(fields[1]);
this.tcgCredentialRevisionLevel = Integer.parseInt(fields[2]);
}
}
}
}
/**
* Get the list of component identifiers if there are any.
* @return the list of component identifiers if there are any
*/
public List<ComponentIdentifier> getComponentIdentifiers() {
try {
PlatformConfiguration platformConfig = getPlatformConfiguration();
if (platformConfig != null) {
return platformConfig.getComponentIdentifier();
}
} catch (IOException e) {
log.error("Unable to parse Platform Configuration from Credential or find"
+ "component identifiers");
}
return Collections.emptyList();
}
/**
* Verify if the AlgorithmIdentifiers are equal.
*
* @param id1 AlgorithIdentifier one
* @param id2 AlgorithIdentifier two
* @return True if are the same, False if not
*/
public static boolean isAlgIdEqual(final AlgorithmIdentifier id1,
final AlgorithmIdentifier id2) {
if (!id1.getAlgorithm().equals(id2.getAlgorithm())) {
return false;
}
if (id1.getParameters() == null) {
if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE)) {
return false;
}
return true;
}
if (id2.getParameters() == null) {
if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE)) {
return false;
}
return true;
}
return id1.getParameters().equals(id2.getParameters());
}
/**
* Get the PolicyQualifier from the Certificate Policies Extension.
*
* @param certificate Attribute Certificate information
* @return Policy Qualifier from the Certificate Policies Extension
*/
public static Map<String, String> getPolicyQualifier(
final AttributeCertificateInfo certificate) {
Preconditions.checkArgument(certificate.getExtensions() != null,
"Platform certificate should have extensions.");
CertificatePolicies certPolicies
= CertificatePolicies.fromExtensions(certificate.getExtensions());
Map<String, String> policyQualifiers = new HashMap<>();
String userNoticeQualifier = "";
String cpsURI = "";
if (certPolicies != null) {
// Must contain at least one Policy
for (PolicyInformation policy : certPolicies.getPolicyInformation()) {
for (ASN1Encodable pQualifierInfo: policy.getPolicyQualifiers().toArray()) {
PolicyQualifierInfo info = PolicyQualifierInfo.getInstance(pQualifierInfo);
// Subtract the data based on the OID
switch (info.getPolicyQualifierId().getId()) {
case POLICY_QUALIFIER_CPSURI:
cpsURI = DERIA5String.getInstance(info.getQualifier()).getString();
break;
case POLICY_QUALIFIER_USER_NOTICE:
UserNotice userNotice = UserNotice.getInstance(info.getQualifier());
userNoticeQualifier = userNotice.getExplicitText().getString();
break;
default:
break;
}
}
}
}
// Add to map
policyQualifiers.put("userNotice", userNoticeQualifier);
policyQualifiers.put("cpsURI", cpsURI);
return policyQualifiers;
}
}

View File

@ -0,0 +1,300 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.Getter;
import lombok.Setter;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERIA5String;
/**
* Basic class that handle CommonCriteriaMeasures for the Platform Certificate
* Attribute.
* <pre>
* CommonCriteriaMeasures ::= SEQUENCE {
* version IA5STRING (SIZE (1..STRMAX)), "2.2" or "3.1";
* assurancelevel EvaluationAssuranceLevel,
* evaluationStatus EvaluationStatus,
* plus BOOLEAN DEFAULT FALSE,
* strengthOfFunction [0] IMPLICIT StrengthOfFunction OPTIONAL,
* profileOid [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
* profileUri [2] IMPLICIT URIReference OPTIONAL,
* targetOid [3] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
* targetUri [4] IMPLICIT URIReference OPTIONAL }
* </pre>
*/
@Getter @Setter
public class CommonCriteriaMeasures {
private static final int STRENGTH_OF_FUNCTION = 0;
private static final int PROFILE_OID = 1;
private static final int PROFILE_URI = 2;
private static final int TARGET_OID = 3;
private static final int TARGET_URI = 4;
/**
* A type to handle the evaluation status used in the Common Criteria Measurement.
* Ordering of enum types is intentional and their ordinal values correspond to enum
* values in the TCG spec.
*
* <pre>
* EvaluationStatus ::= ENUMERATED {
* designedToMeet (0),
* evaluationInProgress (1),
* evaluationCompleted (2) }
* </pre>
*/
public enum EvaluationStatus {
/**
* Evaluation designed to meet.
*/
DESIGNEDTOMEET("designed To Meet"),
/**
* Evaluation in progress.
*/
EVALUATIONINPROGRESS("evaluation In Progress"),
/**
* Evaluation completed.
*/
EVALUATIONCOMPLETED("evaluation Completed");
@Getter
private final String value;
/**
* Basic constructor.
* @param value string containing the value.
*/
EvaluationStatus(final String value) {
this.value = value;
}
}
/**
* A type to handle the strength of function used in the Common Criteria Measurement.
* Ordering of enum types is intentional and their ordinal values correspond to enum
* values in the TCG spec.
*
* <pre>
* StrengthOfFunction ::= ENUMERATED {
* basic (0),
* medium (1),
* high (2) }
* </pre>
*/
public enum StrengthOfFunction {
/**
* Basic function.
*/
BASIC("basic"),
/**
* Medium function.
*/
MEDIUM("medium"),
/**
* Hight function.
*/
HIGH("high");
@Getter
private final String value;
/**
* Basic constructor.
* @param value string containing the value.
*/
StrengthOfFunction(final String value) {
this.value = value;
}
}
/**
* A type to handle the evaluation assurance aevel used in the Common Criteria Measurement.
* Ordering of enum types is intentional and their ordinal values correspond to enum
* values in the TCG spec.
*
* <pre>
* EvaluationAssuranceLevel ::= ENUMERATED {
* levell (1),
* level2 (2),
* level3 (3),
* level4 (4),
* level5 (5),
* level6 (6),
* level7 (7) }
* </pre>
*/
public enum EvaluationAssuranceLevel {
/**
* Evaluation Assurance Level 1.
*/
LEVEL1("level 1"),
/**
* Evaluation Assurance Level 2.
*/
LEVEL2("level 2"),
/**
* Evaluation Assurance Level 3.
*/
LEVEL3("level 3"),
/**
* Evaluation Assurance Level 4.
*/
LEVEL4("level 4"),
/**
* Evaluation Assurance Level 5.
*/
LEVEL5("level 5"),
/**
* Evaluation Assurance Level 6.
*/
LEVEL6("level 6"),
/**
* Evaluation Assurance Level 7.
*/
LEVEL7("level 7");
@Getter
private final String value;
/**
* Basic constructor.
* @param value string containing the value.
*/
EvaluationAssuranceLevel(final String value) {
this.value = value;
}
}
private DERIA5String version;
private EvaluationAssuranceLevel assuranceLevel;
private EvaluationStatus evaluationStatus;
private ASN1Boolean plus;
private StrengthOfFunction strengthOfFunction;
private ASN1ObjectIdentifier profileOid;
private URIReference profileUri;
private ASN1ObjectIdentifier targetOid;
private URIReference targetUri;
/**
* Default constructor.
*/
public CommonCriteriaMeasures() {
this.version = null;
this.assuranceLevel = null;
this.evaluationStatus = null;
this.plus = ASN1Boolean.FALSE;
this.strengthOfFunction = null;
this.profileOid = null;
this.profileUri = null;
this.targetOid = null;
this.targetUri = null;
}
/**
* Constructor given the SEQUENCE that contains Common Criteria Measures.
* @param sequence containing the the common criteria measures
* @throws IllegalArgumentException if there was an error on the parsing
*/
public CommonCriteriaMeasures(final ASN1Sequence sequence) throws IllegalArgumentException {
//Get all the mandatory values
int index = 0;
version = DERIA5String.getInstance(sequence.getObjectAt(index));
++index;
ASN1Enumerated enumarated = ASN1Enumerated.getInstance(sequence.getObjectAt(index));
++index;
//Throw exception when is not between 1 and 7
if (enumarated.getValue().intValue() <= 0
|| enumarated.getValue().intValue() > EvaluationAssuranceLevel.values().length) {
throw new IllegalArgumentException("Invalid assurance level.");
}
assuranceLevel = EvaluationAssuranceLevel.values()[enumarated.getValue().intValue() - 1];
enumarated = ASN1Enumerated.getInstance(sequence.getObjectAt(index));
++index;
evaluationStatus = EvaluationStatus.values()[enumarated.getValue().intValue()];
//Default plus value
plus = ASN1Boolean.FALSE;
//Current sequence index
if (sequence.getObjectAt(index).toASN1Primitive() instanceof ASN1Boolean) {
plus = ASN1Boolean.getInstance(sequence.getObjectAt(index));
index++;
}
//Optional values (default to null or empty)
strengthOfFunction = null;
profileOid = null;
profileUri = null;
targetOid = null;
targetUri = null;
//Sequence for the URIReference
ASN1Sequence uriSequence;
//Continue reading the sequence
for (; index < sequence.size(); index++) {
ASN1TaggedObject taggedObj = ASN1TaggedObject.getInstance(sequence.getObjectAt(index));
switch (taggedObj.getTagNo()) {
case STRENGTH_OF_FUNCTION:
enumarated = ASN1Enumerated.getInstance(taggedObj, false);
strengthOfFunction
= StrengthOfFunction.values()[enumarated.getValue().intValue()];
break;
case PROFILE_OID:
profileOid = ASN1ObjectIdentifier.getInstance(taggedObj, false);
break;
case PROFILE_URI:
uriSequence = ASN1Sequence.getInstance(taggedObj, false);
profileUri = new URIReference(uriSequence);
break;
case TARGET_OID:
targetOid = ASN1ObjectIdentifier.getInstance(taggedObj, false);
break;
case TARGET_URI:
uriSequence = ASN1Sequence.getInstance(taggedObj, false);
targetUri = new URIReference(uriSequence);
break;
default:
throw new IllegalArgumentException("Common criteria measures contains "
+ "invalid tagged object.");
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ComponentIdentifier{");
sb.append("version=").append(version.toString());
sb.append(", assuranceLevel=").append(assuranceLevel.getValue());
sb.append(", evaluationStatus=").append(evaluationStatus.getValue());
sb.append(", plus=").append(plus.toString());
//Not null optional objects
sb.append(", strengthOfFunction=");
if (strengthOfFunction != null) {
sb.append(strengthOfFunction.getValue());
}
sb.append(", profileOid=");
if (profileOid != null) {
sb.append(profileOid.getId());
}
sb.append(", profileUri=");
if (profileUri != null) {
sb.append(profileUri.toString());
}
sb.append(", targetOid=");
if (targetOid != null) {
sb.append(targetOid.getId());
}
sb.append(", targetUri=");
if (targetUri != null) {
sb.append(targetUri.toString());
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,91 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERUTF8String;
/**
* Basic class that handle component addresses from the component identifier.
* <pre>
* componentAddress ::= SEQUENCE {
* addressType AddressType,
* addressValue UTF8String (SIZE (1..STRMAX)) }
* where STRMAX is 256
* </pre>
*/
@Getter
@Setter
@AllArgsConstructor
public class ComponentAddress {
/**
* Number of identifiers that a component address must have.
*/
public static final int IDENTIFIER_NUMBER = 2;
private static final String ETHERNET_MAC = "2.23.133.17.1";
private static final String WLAN_MAC = "2.23.133.17.2";
private static final String BLUETOOTH_MAC = "2.23.133.17.3";
private ASN1ObjectIdentifier addressType;
private DERUTF8String addressValue;
/**
* Default constructor.
*/
public ComponentAddress() {
addressType = null;
addressValue = null;
}
/**
* Constructor given the SEQUENCE that contains the type and value for the
* component address.
*
* @param sequence containing the type and value for the component address
* @throws IllegalArgumentException if there was an error on the parsing
*/
public ComponentAddress(final ASN1Sequence sequence) throws IllegalArgumentException {
//Check if the sequence contains the two values required
if (sequence.size() != IDENTIFIER_NUMBER) {
throw new IllegalArgumentException("Component address does not contain "
+ "all the required fields.");
}
addressType = ASN1ObjectIdentifier.getInstance(sequence.getObjectAt(0));
addressValue = DERUTF8String.getInstance(sequence.getObjectAt(1));
}
/**
* Get the string value for the address type.
* @return the string value for the address type
*/
public String getAddressTypeValue() {
String typeValue;
switch (this.addressType.getId()) {
case ETHERNET_MAC:
typeValue = "ethernet mac";
break;
case WLAN_MAC:
typeValue = "wlan mac";
break;
case BLUETOOTH_MAC:
typeValue = "bluetooth mac";
break;
default:
typeValue = "unknown mac";
break;
}
return typeValue;
}
@Override
public String toString() {
return "ComponentAddress{"
+ "addressType=" + addressType.getId()
+ ", addressValue=" + addressValue.getString()
+ '}';
}
}

View File

@ -0,0 +1,248 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonObject.Member;
import hirs.utils.JsonUtils;
import lombok.Getter;
import java.nio.file.FileSystems;
import java.nio.file.Path;
/**
* <p>
* This class parses the associated component identifier located in Platform
* Certificates and maps them to the corresponding string representation found
* in the associated JSON file. If the value can not be found, either because
* the provided value is malformed or doesn't exist in the mapping, then values
* returned will not match what is expected. This class will return Unknown as a
* category and None as the component which is not a valid mapping. This is
* because None is a category and Unknown is a component identifier.
* </p>
* <pre>
* componentClass ::= SEQUENCE {
* componentClassRegistry ComponentClassRegistry,
* componentClassValue OCTET STRING SIZE(4) ) }
* </pre>
*
* A note for the future.
*/
public class ComponentClass {
private static final String TCG_COMPONENT_REGISTRY = "2.23.133.18.3.1";
private static final String SMBIOS_COMPONENT_REGISTRY = "2.23.133.18.3.3";
private static final Path JSON_PATH = FileSystems.getDefault()
.getPath("/opt", "hirs", "default-properties", "component-class.json");
// private static final Path JSON_PATH = FileSystems.getDefault()
// .getPath("/opt", "hirs", "default-properties", "component-class.json");
private static final String OTHER_STRING = "Other";
private static final String UNKNOWN_STRING = "Unknown";
private static final String NONE_STRING = "None";
// Used to indicate that the component string value provided is erroneous
private static final String ERROR = "-1";
private static final int MID_INDEX = 4;
/**
* All TCG categories have Other and Unknown as the first 2 values.
*/
private static final String OTHER = "0000";
private static final String UNKNOWN = "0001";
@Getter
private String category, categoryStr;
@Getter
private String component, componentStr;
private String registryType;
private String componentIdentifier;
/**
* Default class constructor.
*/
public ComponentClass() {
this("TCG", JSON_PATH, UNKNOWN);
}
/**
* Class Constructor that takes a String representation of the component
* value.
*
* @param registryOid the decimal notation for the type of registry
* @param componentIdentifier component value
*/
public ComponentClass(final String registryOid, final String componentIdentifier) {
this(registryOid, JSON_PATH, componentIdentifier);
}
/**
* Class Constructor that takes a String representation of the component
* value.
*
* @param componentClassPath file path for the json
* @param componentIdentifier component value
*/
public ComponentClass(final Path componentClassPath, final String componentIdentifier) {
this(TCG_COMPONENT_REGISTRY, componentClassPath, componentIdentifier);
}
/**
* Main Class Constructor that takes in an integer representation of the
* component value. Sets main class variables to default values and then
* matches the value against defined values in the associated JSON file.
*
* @param registryOid the decimal notation for the type of registry
* @param componentClassPath file path for the json
* @param componentIdentifier component value
*/
public ComponentClass(final String registryOid,
final Path componentClassPath,
final String componentIdentifier) {
this.category = OTHER;
this.component = NONE_STRING;
if (componentIdentifier == null || componentIdentifier.isEmpty()) {
this.componentIdentifier = "";
} else {
this.componentIdentifier = verifyComponentValue(componentIdentifier);
}
switch (registryOid) {
case TCG_COMPONENT_REGISTRY -> registryType = "TCG";
case SMBIOS_COMPONENT_REGISTRY -> registryType = "SMBIOS";
default -> registryType = UNKNOWN_STRING;
}
switch (this.componentIdentifier) {
case OTHER:
this.categoryStr = NONE_STRING;
this.component = OTHER;
this.componentStr = OTHER_STRING;
break;
case UNKNOWN:
case "":
this.categoryStr = NONE_STRING;
this.component = UNKNOWN;
this.componentStr = UNKNOWN_STRING;
break;
case ERROR:
// Number Format Exception
break;
default:
this.category = this.componentIdentifier.substring(0, MID_INDEX) + this.category;
this.component = OTHER + this.componentIdentifier.substring(MID_INDEX);
findStringValues(JsonUtils.getSpecificJsonObject(componentClassPath, registryType));
break;
}
}
/**
* This is the main way this class will be referenced and how it
* will be displayed on the portal.
* @return String combination of category and component.
*/
@Override
public String toString() {
String resultString;
if (componentStr.equals(UNKNOWN_STRING) || component.equals(OTHER_STRING)) {
resultString = String.format("%s%n%s", registryType, categoryStr);
} else {
resultString = String.format("%s%n%s - %s", registryType, categoryStr, componentStr);
}
return resultString;
}
/**
* Getter for the Category mapped to the associated value in.
*
* @param categories a JSON object associated with mapped categories in file
* {}@link componentIdentifier}.
*/
private void findStringValues(final JsonObject categories) {
String categoryID;
String componentMask;
boolean found = false;
if (categories != null) {
for (String name : categories.names()) {
categoryID = verifyComponentValue(categories.get(name)
.asObject().get("ID").asString());
componentMask = componentIdentifier.substring(MID_INDEX);
// check for the correct flag
if (categoryMatch(componentIdentifier.substring(0, MID_INDEX),
categoryID.substring(0, MID_INDEX))) {
found = true;
JsonObject componentTypes = categories.get(name)
.asObject().get("Types").asObject();
categoryStr = name;
switch (componentMask) {
case OTHER -> componentStr = OTHER_STRING;
case UNKNOWN -> componentStr = UNKNOWN_STRING;
default -> getComponent(componentTypes);
}
}
}
}
if (!found) {
this.categoryStr = NONE_STRING;
this.componentStr = UNKNOWN_STRING;
}
}
/**
* Returns the value of the comparison between a category and the what's in the id.
* @param category the category to compare
* @param componentId the id value to compare
* @return true if they match
*/
public boolean categoryMatch(final String category, final String componentId) {
return category.equals(componentId);
}
/**
* Getter for the component associated with the component JSON Object mapped
* in the JSON file.
*
* @param components JSON Object for the categories components
*/
private void getComponent(final JsonObject components) {
String typeID;
if (components != null) {
for (Member member : components) {
typeID = verifyComponentValue(member.getName());
if (component.equals(typeID)) {
componentStr = member.getValue().asString();
}
}
}
}
/**
* This method converts the string representation of the component ID into
* an integer. Or throws and error if the format is in error.
*
* @param component string representation of the component ID
* @return the int representation of the component
*/
private static String verifyComponentValue(final String component) {
String componentValue = ERROR;
if (component != null) {
try {
if (component.contains("x")) {
componentValue = component.substring(component.indexOf("x") + 1);
} else {
if (component.contains("#")) {
componentValue = component.replace("#", "");
} else {
return component;
}
}
} catch (NumberFormatException nfEx) {
//invalid entry
}
}
return componentValue;
}
}

View File

@ -0,0 +1,238 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERUTF8String;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* Basic class that handle component identifiers from the Platform Configuration
* Attribute.
* <pre>
* ComponentIdentifier ::= SEQUENCE {
* componentManufacturer UTF8String (SIZE (1..STRMAX)),
* componentModel UTF8String (SIZE (1..STRMAX)),
* componentSerial[0] IMPLICIT UTF8String (SIZE (1..STRMAX)) OPTIONAL,
* componentRevision [1] IMPLICIT UTF8String (SIZE (1..STRMAX)) OPTIONAL,
* componentManufacturerId [2] IMPLICIT PrivateEnterpriseNumber OPTIONAL,
* fieldReplaceable [3] IMPLICIT BOOLEAN OPTIONAL,
* componentAddress [4] IMPLICIT
* SEQUENCE(SIZE(1..CONFIGMAX)) OF ComponentAddress OPTIONAL}
* where STRMAX is 256, CONFIGMAX is 32
* </pre>
*/
@Getter
@Setter
@AllArgsConstructor
@EqualsAndHashCode
public class ComponentIdentifier {
/**
* Variable for components that aren't set.
*/
public static final String EMPTY_COMPONENT = "[Empty]";
/**
* Variable for components that aren't set.
*/
public static final String NOT_SPECIFIED_COMPONENT = "Not Specified";
/**
* Maximum number of configurations.
*/
public static final int CONFIGMAX = 32;
private static final int MANDATORY_ELEMENTS = 2;
// optional sequence objects
/**
* Static variable indicated array position for the serial number.
*/
protected static final int COMPONENT_SERIAL = 0;
/**
* Static variable indicated array position for the revision info.
*/
protected static final int COMPONENT_REVISION = 1;
/**
* Static variable indicated array position for the manufacturer id.
*/
protected static final int COMPONENT_MANUFACTURER_ID = 2;
/**
* Static variable indicated array position for the field replaceable value.
*/
protected static final int FIELD_REPLACEABLE = 3;
/**
* Static variable indicated array position for the component address.
*/
protected static final int COMPONENT_ADDRESS = 4;
private DERUTF8String componentManufacturer;
private DERUTF8String componentModel;
private DERUTF8String componentSerial;
private DERUTF8String componentRevision;
private ASN1ObjectIdentifier componentManufacturerId;
private ASN1Boolean fieldReplaceable;
private List<ComponentAddress> componentAddress;
private boolean validationResult = true;
/**
* Default constructor.
*/
public ComponentIdentifier() {
componentManufacturer = new DERUTF8String(NOT_SPECIFIED_COMPONENT);
componentModel = new DERUTF8String(NOT_SPECIFIED_COMPONENT);
componentSerial = new DERUTF8String(StringUtils.EMPTY);
componentRevision = new DERUTF8String(StringUtils.EMPTY);
componentManufacturerId = null;
fieldReplaceable = null;
componentAddress = new ArrayList<>();
}
/**
* Constructor given the components values.
*
* @param componentManufacturer represents the component manufacturer
* @param componentModel represents the component model
* @param componentSerial represents the component serial number
* @param componentRevision represents the component revision
* @param componentManufacturerId represents the component manufacturer ID
* @param fieldReplaceable represents if the component is replaceable
* @param componentAddress represents a list of addresses
*/
public ComponentIdentifier(final DERUTF8String componentManufacturer,
final DERUTF8String componentModel,
final DERUTF8String componentSerial,
final DERUTF8String componentRevision,
final ASN1ObjectIdentifier componentManufacturerId,
final ASN1Boolean fieldReplaceable,
final List<ComponentAddress> componentAddress) {
this.componentManufacturer = componentManufacturer;
this.componentModel = componentModel;
this.componentSerial = componentSerial;
this.componentRevision = componentRevision;
this.componentManufacturerId = componentManufacturerId;
this.fieldReplaceable = fieldReplaceable;
this.componentAddress = componentAddress;
}
/**
* Constructor given the SEQUENCE that contains Component Identifier.
* @param sequence containing the the component identifier
* @throws IllegalArgumentException if there was an error on the parsing
*/
public ComponentIdentifier(final ASN1Sequence sequence) throws IllegalArgumentException {
// set all optional values to default in case they aren't set.
this();
//Check if it have a valid number of identifiers
if (sequence.size() < MANDATORY_ELEMENTS) {
throw new IllegalArgumentException("Component identifier do not have required values.");
}
//Mandatory values
componentManufacturer = DERUTF8String.getInstance(sequence.getObjectAt(0));
componentModel = DERUTF8String.getInstance(sequence.getObjectAt(1));
//Continue reading the sequence if it does contain more than 2 values
for (int i = 2; i < sequence.size(); i++) {
ASN1TaggedObject taggedObj = ASN1TaggedObject.getInstance(sequence.getObjectAt(i));
switch (taggedObj.getTagNo()) {
case COMPONENT_SERIAL:
componentSerial = DERUTF8String.getInstance(taggedObj, false);
break;
case COMPONENT_REVISION:
componentRevision = DERUTF8String.getInstance(taggedObj, false);
break;
case COMPONENT_MANUFACTURER_ID:
componentManufacturerId = ASN1ObjectIdentifier.getInstance(taggedObj, false);
break;
case FIELD_REPLACEABLE:
fieldReplaceable = ASN1Boolean.getInstance(taggedObj, false);
break;
case COMPONENT_ADDRESS:
ASN1Sequence addressesSequence = ASN1Sequence.getInstance(taggedObj, false);
componentAddress = retrieveComponentAddress(addressesSequence);
break;
default:
throw new IllegalArgumentException("Component identifier contains "
+ "invalid tagged object.");
}
}
}
/**
* Get all the component addresses inside the sequence.
*
* @param sequence that contains the component addresses.
* @return list of component addresses inside the sequence
* @throws IllegalArgumentException if there was an error on the parsing
*/
public static List<ComponentAddress> retrieveComponentAddress(final ASN1Sequence sequence)
throws IllegalArgumentException {
List<ComponentAddress> addresses;
addresses = new ArrayList<>();
if (sequence.size() > CONFIGMAX) {
throw new IllegalArgumentException("Component identifier contains invalid number "
+ "of component addresses.");
}
//Get the components
for (int i = 0; i < sequence.size(); i++) {
ASN1Sequence address = ASN1Sequence.getInstance(sequence.getObjectAt(i));
addresses.add(new ComponentAddress(address));
}
return Collections.unmodifiableList(addresses);
}
/**
* @return indicates the type of platform certificate
*/
public boolean isVersion2() {
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ComponentIdentifier{");
sb.append("componentManufacturer=").append(componentManufacturer.getString());
sb.append(", componentModel=").append(componentModel.getString());
//Optional not null values
sb.append(", componentSerial=");
if (componentSerial != null) {
sb.append(componentSerial.getString());
}
sb.append(", componentRevision=");
if (componentRevision != null) {
sb.append(componentRevision.getString());
}
sb.append(", componentManufacturerId=");
if (componentManufacturerId != null) {
sb.append(componentManufacturerId.getId());
}
sb.append(", fieldReplaceable=");
if (fieldReplaceable != null) {
sb.append(fieldReplaceable.toString());
}
sb.append(", componentAddress=");
if (componentAddress.size() > 0) {
sb.append(componentAddress
.stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
sb.append(", certificateIdentifier=");
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,122 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERIA5String;
/**
* Basic class that handle FIPS Level.
* <pre>
* FIPSLevel ::= SEQUENCE {
* version IA5STRING (SIZE (1..STRMAX)), -- "140-1" or "140-2"
* level SecurityLevel,
* plus BOOLEAN DEFAULT FALSE }
* </pre>
*/
@AllArgsConstructor
public class FIPSLevel {
private static final int MAX_SEQUENCE_SIZE = 3;
/**
* A type to handle the security Level used in the FIPS Level.
* Ordering of enum types is intentional and their ordinal values correspond to enum
* values in the TCG spec.
*
* <pre>
* SecurityLevel ::= ENUMERATED {
* level1 (1),
* level2 (2),
* level3 (3),
* level4 (4) }
* </pre>
*/
public enum SecurityLevel {
/**
* Security Level 1.
*/
LEVEL1("level 1"),
/**
* Security Level 2.
*/
LEVEL2("level 2"),
/**
* Security Level 3.
*/
LEVEL3("level 3"),
/**
* Security Level 4.
*/
LEVEL4("level 4");
private final String value;
/**
* Basic constructor.
* @param value string containing the value.
*/
SecurityLevel(final String value) {
this.value = value;
}
/**
* Get the string value from the StrengthOfFunction.
* @return the string containing the value.
*/
public String getValue() {
return this.value;
}
}
@Getter @Setter
private DERIA5String version;
@Getter @Setter
private SecurityLevel level;
@Getter @Setter
private ASN1Boolean plus;
/**
* Default constructor.
*/
public FIPSLevel() {
version = null;
level = null;
plus = null;
}
/**
* Constructor given the SEQUENCE that contains the FIPLevel Object.
*
* @param sequence containing the FIPS Level Object
* @throws IllegalArgumentException if there was an error on the parsing
*/
public FIPSLevel(final ASN1Sequence sequence) throws IllegalArgumentException {
//Get version
version = DERIA5String.getInstance(sequence.getObjectAt(0));
//Get and validate level
ASN1Enumerated enumarated = ASN1Enumerated.getInstance(sequence.getObjectAt(1));
//Throw exception when is not between 1 and 7
if (enumarated.getValue().intValue() <= 0
|| enumarated.getValue().intValue() > SecurityLevel.values().length) {
throw new IllegalArgumentException("Invalid security level on FIPSLevel.");
}
level = SecurityLevel.values()[enumarated.getValue().intValue() - 1];
//Check if there is another value on the sequence for the plus
plus = ASN1Boolean.FALSE; //Default to false
if (sequence.size() == MAX_SEQUENCE_SIZE) {
plus = ASN1Boolean.getInstance(sequence.getObjectAt(2));
}
}
@Override
public String toString() {
return "FIPSLevel{"
+ "version=" + version.getString()
+ ", level=" + level.getValue()
+ ", plus=" + plus.toString()
+ '}';
}
}

View File

@ -0,0 +1,104 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Abstract class that provides base info for Platform Configuration of
* the Platform Certificate Attribute.
*/
@AllArgsConstructor
public abstract class PlatformConfiguration {
private List<ComponentIdentifier> componentIdentifier;
@Getter @Setter
private URIReference componentIdentifierUri;
private List<PlatformProperty> platformProperties;
@Getter @Setter
private URIReference platformPropertiesUri;
/**
* Default constructor.
*/
public PlatformConfiguration() {
this.componentIdentifier = new ArrayList<>();
this.componentIdentifierUri = null;
this.platformProperties = new ArrayList<>();
this.platformPropertiesUri = null;
}
/**
* Constructor given the Platform Configuration values.
*
* @param componentIdentifier list containing all the components inside the
* Platform Configuration.
* @param platformProperties list containing all the properties inside the
* Platform Configuration.
* @param platformPropertiesUri object containing the URI Reference
*/
public PlatformConfiguration(final List<ComponentIdentifier> componentIdentifier,
final List<PlatformProperty> platformProperties,
final URIReference platformPropertiesUri) {
this.componentIdentifier = componentIdentifier;
this.platformProperties = platformProperties;
this.platformPropertiesUri = platformPropertiesUri;
}
/**
* @return the componentIdentifier
*/
public List<ComponentIdentifier> getComponentIdentifier() {
return Collections.unmodifiableList(componentIdentifier);
}
/**
* Add function for the component identifier array.
* @param componentIdentifier object to add
* @return status of the add, if successful or not
*/
protected boolean add(final ComponentIdentifier componentIdentifier) {
if (this.componentIdentifier != null) {
return this.componentIdentifier.add(componentIdentifier);
}
return false;
}
/**
* @param componentIdentifier the componentIdentifier to set
*/
public void setComponentIdentifier(final List<ComponentIdentifier> componentIdentifier) {
this.componentIdentifier = componentIdentifier;
}
/**
* @return the platformProperties
*/
public List<PlatformProperty> getPlatformProperties() {
return Collections.unmodifiableList(platformProperties);
}
/**
* Add function for the platform property array.
* @param platformProperty property object to add
* @return status of the add, if successful or not
*/
protected boolean add(final PlatformProperty platformProperty) {
if (this.platformProperties != null) {
return this.platformProperties.add(platformProperty);
}
return false;
}
/**
* @param platformProperties the platformProperties to set
*/
public void setPlatformProperties(final List<PlatformProperty> platformProperties) {
this.platformProperties = platformProperties;
}
}

View File

@ -0,0 +1,105 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import java.util.ArrayList;
import java.util.stream.Collectors;
/**
* Basic class that handle Platform Configuration for the Platform Certificate
* Attribute.
* <pre>
* PlatformConfiguration ::= SEQUENCE {
* componentIdentifier [0] IMPLICIT SEQUENCE(SIZE(1..CONFIGMAX)) OF
* ComponentIdentifier OPTIONAL,
* platformProperties [1] IMPLICIT SEQUENCE(SIZE(1..CONFIGMAX)) OF Properties OPTIONAL,
* platformPropertiesUri [2] IMPLICIT URIReference OPTIONAL }
* </pre>
*/
public class PlatformConfigurationV1 extends PlatformConfiguration {
private static final int COMPONENT_IDENTIFIER = 0;
private static final int PLATFORM_PROPERTIES = 1;
private static final int PLATFORM_PROPERTIES_URI = 2;
/**
* Constructor given the SEQUENCE that contains Platform Configuration.
* @param sequence containing the the Platform Configuration.
* @throws IllegalArgumentException if there was an error on the parsing
*/
public PlatformConfigurationV1(final ASN1Sequence sequence) throws IllegalArgumentException {
//Default values
setComponentIdentifier(new ArrayList<>());
setPlatformProperties(new ArrayList<>());
setPlatformPropertiesUri(null);
for (int i = 0; i < sequence.size(); i++) {
ASN1TaggedObject taggedSequence
= ASN1TaggedObject.getInstance(sequence.getObjectAt(i));
//Set information based on the set tagged
switch (taggedSequence.getTagNo()) {
case COMPONENT_IDENTIFIER:
//Get componentIdentifier
ASN1Sequence componentConfiguration
= ASN1Sequence.getInstance(taggedSequence, false);
//Get and set all the component values
for (int j = 0; j < componentConfiguration.size(); j++) {
//DERSequence with the components
ASN1Sequence component
= ASN1Sequence.getInstance(componentConfiguration.getObjectAt(j));
add(new ComponentIdentifier(component));
}
break;
case PLATFORM_PROPERTIES:
//Get platformProperties
ASN1Sequence properties = ASN1Sequence.getInstance(taggedSequence, false);
//Get and set all the properties values
for (int j = 0; j < properties.size(); j++) {
//DERSequence with the components
ASN1Sequence property = ASN1Sequence.getInstance(properties.getObjectAt(j));
add(new PlatformProperty(property));
}
break;
case PLATFORM_PROPERTIES_URI:
//Get platformPropertiesURI
ASN1Sequence propertiesUri = ASN1Sequence.getInstance(taggedSequence, false);
//Save properties URI
setPlatformPropertiesUri(new URIReference(propertiesUri));
break;
default:
break;
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("PlatformConfiguration{");
sb.append("componentIdentifier=");
if (getComponentIdentifier().size() > 0) {
sb.append(getComponentIdentifier()
.stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
sb.append(", platformProperties=");
if (getPlatformProperties().size() > 0) {
sb.append(getPlatformProperties()
.stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
sb.append(", platformPropertiesUri=");
if (getPlatformPropertiesUri() != null) {
sb.append(getPlatformPropertiesUri().toString());
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,67 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERUTF8String;
/**
*
* Basic class that handles a single property for the platform configuration.
* <pre>
* Properties ::= SEQUENCE {
* propertyName UTF8String (SIZE (1..STRMAX)),
* propertyValue UTF8String (SIZE (1..STRMAX) }
*
* </pre>
*/
@Getter
@Setter
@AllArgsConstructor
public class PlatformProperty {
private static final String NOT_SPECIFIED = "Not Specified";
/**
* Number of identifiers for version 1.
*/
protected static final int IDENTIFIER_NUMBER = 2;
private DERUTF8String propertyName;
private DERUTF8String propertyValue;
/**
* Default constructor.
*/
public PlatformProperty() {
this.propertyName = new DERUTF8String(NOT_SPECIFIED);
this.propertyValue = new DERUTF8String(NOT_SPECIFIED);
}
/**
* Constructor given the SEQUENCE that contains the name and value for the
* platform property.
*
* @param sequence containing the name and value of the platform property
* @throws IllegalArgumentException if there was an error on the parsing
*/
public PlatformProperty(final ASN1Sequence sequence) throws IllegalArgumentException {
// Check if the sequence contains the two values required
if (sequence.size() != IDENTIFIER_NUMBER) {
throw new IllegalArgumentException("Platform properties does not contain all "
+ "the required fields.");
}
this.propertyName = DERUTF8String.getInstance(sequence.getObjectAt(0));
this.propertyValue = DERUTF8String.getInstance(sequence.getObjectAt(1));
}
@Override
public String toString() {
return "PlatformProperty{"
+ "propertyName=" + propertyName.getString()
+ ", propertyValue=" + propertyValue.getString()
+ "}";
}
}

View File

@ -0,0 +1,282 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERIA5String;
import java.math.BigInteger;
/**
* Basic class that handle component identifiers from the Platform Configuration
* Attribute.
* <pre>
* TBBSecurityAssertions ::= SEQUENCE {
* version Version DEFAULT v1,
* ccInfo [0] IMPLICIT CommonCriteriaMeasures OPTIONAL,
* fipsLevel [1] IMPLICIT FIPSLevel OPTIONAL,
* rtmType [2] IMPLICIT MeasurementRootType OPTIONAL,
* iso9000Certified BOOLEAN DEFAULT FALSE,
* iso9000Uri IA5STRING (SIZE (1..URIMAX)) OPTIONAL }
* </pre>
*/
@AllArgsConstructor
public class TBBSecurityAssertion {
private static final int CCINFO = 0;
private static final int FIPSLEVEL = 1;
private static final int RTMTYPE = 2;
/**
* A type to handle the evaluation status used in the Common Criteria Measurement.
* Ordering of enum types is intentional and their ordinal values correspond to enum
* values in the TCG spec.
*
* <pre>
* MeasurementRootType ::= ENUMERATED {
* static (0),
* dynamic (1),
* nonHost (2),
* hybrid (3),
* physical (4),
* virtual (5) }
* </pre>
*/
public enum MeasurementRootType {
/**
* Static measurement root type.
*/
STATIC("static"),
/**
* Dynamic measurement root type.
*/
DYNAMIC("dynamic"),
/**
* Non-Host measurement root type.
*/
NONHOST("nonHost"),
/**
* Hybrid measurement root type.
*/
HYBRID("hybrid"),
/**
* Physical measurement root type.
*/
PHYSICAL("physical"),
/**
* Virtual measurement root type.
*/
VIRTUAL("virtual");
@Getter
private final String value;
/**
* Basic constructor.
* @param value string containing the value.
*/
MeasurementRootType(final String value) {
this.value = value;
}
}
private ASN1Integer version;
private CommonCriteriaMeasures ccInfo;
private FIPSLevel fipsLevel;
private MeasurementRootType rtmType;
private ASN1Boolean iso9000Certified;
private DERIA5String iso9000Uri;
/**
* Default constructor.
*/
public TBBSecurityAssertion() {
version = null;
ccInfo = null;
fipsLevel = null;
rtmType = null;
iso9000Certified = null;
iso9000Uri = null;
}
/**
* Constructor given the SEQUENCE that contains a TBBSecurityAssertion Object.
* @param sequence containing the the TBB Security Assertion
* @throws IllegalArgumentException if there was an error on the parsing
*/
public TBBSecurityAssertion(final ASN1Sequence sequence) throws IllegalArgumentException {
int index = 0;
//sequence size
int sequenceSize = sequence.size();
//Default values
version = new ASN1Integer(BigInteger.valueOf(0)); //Default v1 (0)
ccInfo = null;
fipsLevel = null;
rtmType = null;
iso9000Certified = ASN1Boolean.FALSE;
iso9000Uri = null;
// Only contains defaults
if (sequence.size() == 0) {
return;
}
// Get version if present
if (sequence.getObjectAt(index).toASN1Primitive() instanceof ASN1Integer) {
version = ASN1Integer.getInstance(sequence.getObjectAt(index));
index++;
}
// Check if it's a tag value
while (index < sequenceSize
&& sequence.getObjectAt(index).toASN1Primitive() instanceof ASN1TaggedObject) {
ASN1TaggedObject taggedObj = ASN1TaggedObject.getInstance(sequence.getObjectAt(index));
switch (taggedObj.getTagNo()) {
case CCINFO:
ASN1Sequence cciSequence = ASN1Sequence.getInstance(taggedObj, false);
ccInfo = new CommonCriteriaMeasures(cciSequence);
break;
case FIPSLEVEL:
ASN1Sequence fipsSequence = ASN1Sequence.getInstance(taggedObj, false);
fipsLevel = new FIPSLevel(fipsSequence);
break;
case RTMTYPE:
ASN1Enumerated enumerated = ASN1Enumerated.getInstance(taggedObj, false);
rtmType = MeasurementRootType.values()[enumerated.getValue().intValue()];
break;
default:
throw new IllegalArgumentException("TBB Security Assertion contains "
+ "invalid tagged object.");
}
index++;
}
// Check if it's a boolean
if (index < sequenceSize
&& sequence.getObjectAt(index).toASN1Primitive() instanceof ASN1Boolean) {
iso9000Certified = ASN1Boolean.getInstance(sequence.getObjectAt(index));
index++;
}
// Check if it's a IA5String
if (index < sequenceSize
&& sequence.getObjectAt(index).toASN1Primitive() instanceof DERIA5String) {
iso9000Uri = DERIA5String.getInstance(sequence.getObjectAt(index));
}
}
/**
* @return the version
*/
public ASN1Integer getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(final ASN1Integer version) {
this.version = version;
}
/**
* @return the ccInfo
*/
public CommonCriteriaMeasures getCcInfo() {
return ccInfo;
}
/**
* @param ccInfo the ccInfo to set
*/
public void setCcInfo(final CommonCriteriaMeasures ccInfo) {
this.ccInfo = ccInfo;
}
/**
* @return the fipsLevel
*/
public FIPSLevel getFipsLevel() {
return fipsLevel;
}
/**
* @param fipsLevel the fipsLevel to set
*/
public void setFipsLevel(final FIPSLevel fipsLevel) {
this.fipsLevel = fipsLevel;
}
/**
* @return the rtmType
*/
public MeasurementRootType getRtmType() {
return rtmType;
}
/**
* @param rtmType the rtmType to set
*/
public void setRtmType(final MeasurementRootType rtmType) {
this.rtmType = rtmType;
}
/**
* @return the iso9000Certified
*/
public ASN1Boolean getIso9000Certified() {
return iso9000Certified;
}
/**
* @param iso9000Certified the iso9000Certified to set
*/
public void setIso9000Certified(final ASN1Boolean iso9000Certified) {
this.iso9000Certified = iso9000Certified;
}
/**
* @return the iso9000Uri
*/
public DERIA5String getIso9000Uri() {
return iso9000Uri;
}
/**
* @param iso9000Uri the iso9000Uri to set
*/
public void setIso9000Uri(final DERIA5String iso9000Uri) {
this.iso9000Uri = iso9000Uri;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("TBBSecurityAssertion{");
sb.append("version=").append(version.toString());
//Optional values not null
sb.append(", ccInfo=");
if (ccInfo != null) {
sb.append(ccInfo.toString());
}
sb.append(", fipsLevel=");
if (fipsLevel != null) {
sb.append(fipsLevel.toString());
}
sb.append(", rtmType=");
if (rtmType != null) {
sb.append(rtmType.getValue());
}
sb.append(", iso9000Certified=").append(iso9000Certified.toString());
sb.append(", iso9000Uri=");
if (iso9000Uri != null) {
sb.append(iso9000Uri.getString());
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,121 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.math.BigInteger;
/**
* A class to represent the TPM Security Assertions in an Endorsement Credential as
* defined by the TCG spec for TPM 1.2.
*
* https://www.trustedcomputinggroup.org/wp-content/uploads/IWG-Credential_Profiles_V1_R0.pdf
*
* Future iterations of this code may want to reference
* www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf
* for specifications for TPM 2.0 (pg. 19).
*/
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter @Setter
@Embeddable
public class TPMSecurityAssertions {
/**
* A type to handle the different endorsement key generation types used in the TPM
* Assertions field of an endorsement credential. Ordering of enum types is intentional
* and their ordinal values correspond to enum values in the TCG spec.
*/
public enum EkGenerationType {
/**
* Generated internally within the TPM and cannot be revoked. Enum value of 0.
*/
INTERNAL,
/**
* Generated externally and then inserted under a controlled environment during
* manufacturing. Cannot be revoked. Enum value of 1.
*/
INJECTED,
/**
* Generated internally within the TPM and can be revoked. Enum value of 2.
*/
INTERNAL_REVOCABLE,
/**
* Generated externally and then inserted under a controlled environment during
* manufacturing. Can be revoked. Enum value of 3.
*/
INJECTED_REVOCABLE;
}
/**
* A type to handle the different endorsement key generation locations used in
* specifying the endorsement key generation location and the endorsement key
* certificate generation location in the TPM Assertions field of an endorsement
* credential. Ordering of enum types is intentional and their ordinal values
* correspond to enum values in the TCG spec.
*/
public enum EkGenerationLocation {
/**
* Generated by the TPM Manufacturer. Enum value of 0.
*/
TPM_MANUFACTURER,
/**
* Generated by the Platform Manufacturer. Enum value of 1.
*/
PLATFORM_MANUFACTURER,
/**
* Generated by the endorsement key certificate signer. Enum value of 2.
*/
EK_CERT_SIGNER;
}
@Column
private BigInteger tpmSecAssertsVersion; //default v1
@Column
private boolean fieldUpgradeable; //default false
@Column(nullable = true)
private EkGenerationType ekGenType; //optional
@Column(nullable = true)
private EkGenerationLocation ekGenerationLocation; //optional
@Column(nullable = true)
private EkGenerationLocation ekCertificateGenerationLocation; //optional
// Future work (may need to create other classes):
//private CommonCriteriaMeasures commCritMeasures; //optional
//private FIPSLevel fipsLevel; //optional
//private boolean iso9000Certified; //default false
//private IA5String iso9000Uri; //optional
/**
* Standard constructor that sets required fields. Use accessor methods
* to set optional fields.
* @param version the version of the security assertions
* @param fieldUpgradeable whether or not the security assertions are
* field upgradeable.
*/
public TPMSecurityAssertions(final BigInteger version, final boolean fieldUpgradeable) {
this.tpmSecAssertsVersion = version;
this.fieldUpgradeable = fieldUpgradeable;
}
@Override
public String toString() {
return "TPMSecurityAssertions{"
+ "version=" + tpmSecAssertsVersion
+ ", fieldUpgradeable=" + fieldUpgradeable
+ ", ekGenType=" + ekGenType
+ ", ekGenLoc=" + ekGenerationLocation
+ ", ekCertGenLoc=" + ekCertificateGenerationLocation
+ '}';
}
}

View File

@ -0,0 +1,58 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.math.BigInteger;
/**
* A class to represent the TPM Specification in an Endorsement Credential as
* defined by the TCG spec for TPM 1.2.
*
* https://www.trustedcomputinggroup.org/wp-content/uploads/IWG-Credential_Profiles_V1_R0.pdf
*
* Future iterations of this code may want to reference
* www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf
* for specifications for TPM 2.0.
*/
@EqualsAndHashCode
@NoArgsConstructor(access= AccessLevel.PROTECTED)
@Getter
@Embeddable
public class TPMSpecification {
@Column
private String family;
@Column
private BigInteger level;
@Column
private BigInteger revision;
/**
* Standard constructor.
* @param family the specification family.
* @param level the specification level.
* @param revision the specification revision.
*/
public TPMSpecification(final String family, final BigInteger level,
final BigInteger revision) {
this.family = family;
this.level = level;
this.revision = revision;
}
@Override
public String toString() {
return "TPMSpecification{"
+ "family='" + family + '\''
+ ", level=" + level
+ ", revision=" + revision
+ '}';
}
}

View File

@ -0,0 +1,91 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
/**
*
* Basic class that handle a URIReference object.
* <pre>
* URIReference ::= SEQUENCE {
* uniformResourceIdentifier IA5String (SIZE (1..URIMAX)),
* hashAlgorithm AlgorithmIdentifier OPTIONAL,
* hashValue BIT STRING OPTIONAL
}
* </pre>
*/
@Getter @Setter
@AllArgsConstructor
public class URIReference {
private DERIA5String uniformResourceIdentifier;
private AlgorithmIdentifier hashAlgorithm;
@JsonIgnore
private DERBitString hashValue;
private static final int PLATFORM_PROPERTIES_URI_MAX = 3;
private static final int PLATFORM_PROPERTIES_URI_MIN = 1;
/**
* Default constructor.
*/
public URIReference() {
this.uniformResourceIdentifier = null;
this.hashAlgorithm = null;
this.hashValue = null;
}
/**
* Constructor given the SEQUENCE that contains the URIReference values.
*
* @param sequence containing the name and value of the platform property
* @throws IllegalArgumentException if there was an error on the parsing
*/
public URIReference(final ASN1Sequence sequence) throws IllegalArgumentException {
//Check if the sequence contains the two values required
if (sequence.size() > PLATFORM_PROPERTIES_URI_MAX
|| sequence.size() < PLATFORM_PROPERTIES_URI_MIN) {
throw new IllegalArgumentException("PlatformPropertiesURI contains invalid "
+ "number of fields.");
}
//Get the Platform Configuration URI values
for (int j = 0; j < sequence.size(); j++) {
if (sequence.getObjectAt(j) instanceof DERIA5String) {
this.uniformResourceIdentifier = DERIA5String.getInstance(sequence.getObjectAt(j));
} else if ((sequence.getObjectAt(j) instanceof AlgorithmIdentifier)
|| (sequence.getObjectAt(j) instanceof ASN1Sequence)) {
this.hashAlgorithm =
AlgorithmIdentifier.getInstance(sequence.getObjectAt(j));
} else if (sequence.getObjectAt(j) instanceof DERBitString) {
this.hashValue = DERBitString.getInstance(sequence.getObjectAt(j));
} else {
throw new IllegalArgumentException("Unexpected DER type found. "
+ sequence.getObjectAt(j).getClass().getName() + " found at index " + j + ".");
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("URIReference{");
sb.append("uniformResourceIdentifier=").append(uniformResourceIdentifier.getString());
//Check of optional values are not null
sb.append(", hashAlgorithm=");
if (hashAlgorithm != null) {
sb.append(hashAlgorithm.getAlgorithm().getId());
}
sb.append(", hashValue=");
if (hashValue != null) {
sb.append(hashValue.getString());
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,40 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
/**
* A type to handle the security Level used in the FIPS Level.
* Ordering of enum types is intentional and their ordinal values correspond to enum
* values in the TCG spec.
*
* <pre>
* AttributeStatus ::= ENUMERATED {
* added (0),
* modified (1),
* removed (2) }
* </pre>
*/
@AllArgsConstructor
public enum AttributeStatus {
/**
* Attribute Status for ADDED.
*/
ADDED("added"),
/**
* Attribute Status for MODIFIED.
*/
MODIFIED("modified"),
/**
* Attribute Status for REMOVED.
*/
REMOVED("removed"),
/**
* Attribute Status for EMPTY.
*/
EMPTY_STATUS(StringUtils.EMPTY);
@Getter
private final String value;
}

View File

@ -0,0 +1,127 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2;
import lombok.Getter;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.GeneralName;
import java.math.BigInteger;
/**
* Basic class that handles a the attribute associate with a Certificate
* Identifier for the component.
* <pre>
* CertificateIdentifier::= SEQUENCE {
* attributeCertIdentifier [0] IMPLICIT AttributeCertificateIdentifier OPTIONAL
* genericCertIdentifier [1] IMPLICIT IssuerSerial OPTIONAL }
*
* AttributeCertificateIdentifier ::= SEQUENCE {
* hashAlgorithm AlgorithmIdentifier,
* hashOverSignatureValue OCTET STRING }
*
* IssuerSerial ::= SEQUENCE {
* issuer GeneralNames,
* serial CertificateSerialNumber }
* </pre>
*/
@Getter
public class CertificateIdentifier {
private static final String NOT_SPECIFIED = "Not Specified";
private static final int SEQUENCE_NUMBER = 2;
private static final int ATTRIBUTE_ID_INDEX = 0;
private static final int GENERIC_ID_INDEX = 1;
private String hashAlgorithm;
private String hashSigValue;
private GeneralName issuerDN;
private BigInteger certificateSerialNumber;
/**
* Default constructor.
*/
public CertificateIdentifier() {
hashAlgorithm = NOT_SPECIFIED;
hashSigValue = null;
issuerDN = null;
certificateSerialNumber = BigInteger.ZERO;
}
/**
* Primary constructor for the parsing of the sequence.
* @param sequence containing the name and value of the Certificate Identifier
*/
public CertificateIdentifier(final ASN1Sequence sequence) {
this();
ASN1TaggedObject taggedObj;
for (int i = 0; i < sequence.size(); i++) {
taggedObj = ASN1TaggedObject.getInstance(sequence.getObjectAt(i));
switch (taggedObj.getTagNo()) {
case ATTRIBUTE_ID_INDEX:
// attributecertificateidentifier
parseAttributeCertId(ASN1Sequence.getInstance(taggedObj, false));
break;
case GENERIC_ID_INDEX:
// issuerserial
parseGenericCertId(ASN1Sequence.getInstance(taggedObj, false));
break;
default:
break;
}
}
}
private void parseAttributeCertId(final ASN1Sequence attrCertSeq) {
//Check if it have a valid number of identifiers
if (attrCertSeq.size() != SEQUENCE_NUMBER) {
throw new IllegalArgumentException("CertificateIdentifier"
+ ".AttributeCertificateIdentifier does not have required values.");
}
hashAlgorithm = attrCertSeq.getObjectAt(0).toString();
hashSigValue = attrCertSeq.getObjectAt(1).toString();
}
private void parseGenericCertId(final ASN1Sequence issuerSerialSeq) {
//Check if it have a valid number of identifiers
if (issuerSerialSeq.size() != SEQUENCE_NUMBER) {
throw new IllegalArgumentException("CertificateIdentifier"
+ ".GenericCertificateIdentifier does not have required values.");
}
ASN1Sequence derSequence = DERSequence.getInstance(issuerSerialSeq.getObjectAt(0));
ASN1TaggedObject taggedObj = ASN1TaggedObject.getInstance(derSequence.getObjectAt(0));
issuerDN = GeneralName.getInstance(taggedObj);
certificateSerialNumber = ASN1Integer.getInstance(issuerSerialSeq
.getObjectAt(1)).getValue();
}
/**
* String for the internal data stored.
* @return String representation of the data.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("CertificateIdentifier{");
sb.append("hashAlgorithm=").append(hashAlgorithm);
sb.append(", hashSigValue").append(hashSigValue);
sb.append(", issuerDN=");
if (issuerDN != null) {
sb.append(issuerDN.toString());
}
sb.append(", certificateSerialNumber=");
if (certificateSerialNumber != null) {
sb.append(certificateSerialNumber.toString());
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,251 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentAddress;
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.URIReference;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERUTF8String;
import java.util.List;
import java.util.stream.Collectors;
/**
* Basic class that handle component identifiers from the Platform Configuration
* Attribute.
* <pre>
* ComponentIdentifier ::= SEQUENCE {
* componentManufacturer UTF8String (SIZE (1..STRMAX)),
* componentModel UTF8String (SIZE (1..STRMAX)),
* componentSerial[0] IMPLICIT UTF8String (SIZE (1..STRMAX)) OPTIONAL,
* componentRevision [1] IMPLICIT UTF8String (SIZE (1..STRMAX)) OPTIONAL,
* componentManufacturerId [2] IMPLICIT PrivateEnterpriseNumber OPTIONAL,
* fieldReplaceable [3] IMPLICIT BOOLEAN OPTIONAL,
* componentAddress [4] IMPLICIT
* SEQUENCE(SIZE(1..CONFIGMAX)) OF ComponentAddress OPTIONAL
* componentPlatformCert [5] IMPLICIT CertificateIdentifier OPTIONAL,
* componentPlatformCertUri [6] IMPLICIT URIReference OPTIONAL,
* status [7] IMPLICIT AttributeStatus OPTIONAL }
* where STRMAX is 256, CONFIGMAX is 32
* </pre>
*/
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class ComponentIdentifierV2 extends ComponentIdentifier {
private static final int MANDATORY_ELEMENTS = 3;
// Additional optional identifiers for version 2
private static final int COMPONENT_PLATFORM_CERT = 5;
private static final int COMPONENT_PLATFORM_URI = 6;
private static final int ATTRIBUTE_STATUS = 7;
private ComponentClass componentClass;
private CertificateIdentifier certificateIdentifier;
private URIReference componentPlatformUri;
private AttributeStatus attributeStatus;
/**
* Default constructor.
*/
public ComponentIdentifierV2() {
super();
componentClass = new ComponentClass();
certificateIdentifier = null;
componentPlatformUri = null;
attributeStatus = AttributeStatus.EMPTY_STATUS;
}
/**
* Constructor given the components values.
*
* @param componentClass represent the component type
* @param componentManufacturer represents the component manufacturer
* @param componentModel represents the component model
* @param componentSerial represents the component serial number
* @param componentRevision represents the component revision
* @param componentManufacturerId represents the component manufacturer ID
* @param fieldReplaceable represents if the component is replaceable
* @param componentAddress represents a list of addresses
* @param certificateIdentifier object representing certificate Id
* @param componentPlatformUri object containing the URI Reference
* @param attributeStatus object containing enumerated status
*/
@SuppressWarnings("checkstyle:parameternumber")
public ComponentIdentifierV2(final ComponentClass componentClass,
final DERUTF8String componentManufacturer,
final DERUTF8String componentModel,
final DERUTF8String componentSerial,
final DERUTF8String componentRevision,
final ASN1ObjectIdentifier componentManufacturerId,
final ASN1Boolean fieldReplaceable,
final List<ComponentAddress> componentAddress,
final CertificateIdentifier certificateIdentifier,
final URIReference componentPlatformUri,
final AttributeStatus attributeStatus) {
super(componentManufacturer, componentModel, componentSerial,
componentRevision, componentManufacturerId, fieldReplaceable,
componentAddress);
this.componentClass = componentClass;
// additional optional component identifiers
this.certificateIdentifier = certificateIdentifier;
this.componentPlatformUri = componentPlatformUri;
this.attributeStatus = attributeStatus;
}
/**
* Constructor given the SEQUENCE that contains Component Identifier.
* @param sequence containing the the component identifier
* @throws IllegalArgumentException if there was an error on the parsing
*/
public ComponentIdentifierV2(final ASN1Sequence sequence)
throws IllegalArgumentException {
super();
// Check if it have a valid number of identifiers
if (sequence.size() < MANDATORY_ELEMENTS) {
throw new IllegalArgumentException("Component identifier do not have required values.");
}
int tag = 0;
ASN1Sequence componentIdSeq = ASN1Sequence.getInstance(sequence.getObjectAt(tag));
componentClass = new ComponentClass(componentIdSeq.getObjectAt(tag++).toString(),
DEROctetString.getInstance(componentIdSeq.getObjectAt(tag)).toString());
// Mandatory values
this.setComponentManufacturer(DERUTF8String.getInstance(sequence.getObjectAt(tag++)));
this.setComponentModel(DERUTF8String.getInstance(sequence.getObjectAt(tag++)));
// Continue reading the sequence if it does contain more than 2 values
for (int i = tag; i < sequence.size(); i++) {
ASN1TaggedObject taggedObj = ASN1TaggedObject.getInstance(sequence.getObjectAt(i));
switch (taggedObj.getTagNo()) {
case COMPONENT_SERIAL:
this.setComponentSerial(DERUTF8String.getInstance(taggedObj, false));
break;
case COMPONENT_REVISION:
this.setComponentRevision(DERUTF8String.getInstance(taggedObj, false));
break;
case COMPONENT_MANUFACTURER_ID:
this.setComponentManufacturerId(ASN1ObjectIdentifier
.getInstance(taggedObj, false));
break;
case FIELD_REPLACEABLE:
this.setFieldReplaceable(ASN1Boolean.getInstance(taggedObj, false));
break;
case COMPONENT_ADDRESS:
ASN1Sequence addressesSequence = ASN1Sequence.getInstance(taggedObj, false);
this.setComponentAddress(retrieveComponentAddress(addressesSequence));
break;
case COMPONENT_PLATFORM_CERT:
ASN1Sequence ciSequence = ASN1Sequence.getInstance(taggedObj, false);
certificateIdentifier = new CertificateIdentifier(ciSequence);
break;
case COMPONENT_PLATFORM_URI:
ASN1Sequence uriSequence = ASN1Sequence.getInstance(taggedObj, false);
this.componentPlatformUri = new URIReference(uriSequence);
break;
case ATTRIBUTE_STATUS:
ASN1Enumerated enumerated = ASN1Enumerated.getInstance(taggedObj, false);
this.attributeStatus = AttributeStatus.values()[
enumerated.getValue().intValue()];
break;
default:
throw new IllegalArgumentException("Component identifier contains "
+ "invalid tagged object.");
}
}
}
/**
* @return true if the component has been modified.
*/
public final boolean isAdded() {
return getAttributeStatus() == AttributeStatus.ADDED;
}
/**
* @return true if the component has been modified.
*/
public final boolean isModified() {
return getAttributeStatus() == AttributeStatus.MODIFIED;
}
/**
* @return true if the component has been removed.
*/
public final boolean isRemoved() {
return getAttributeStatus() == AttributeStatus.REMOVED;
}
/**
* @return true if the component status wasn't set.
*/
public final boolean isEmpty() {
return (getAttributeStatus() == AttributeStatus.EMPTY_STATUS)
|| (getAttributeStatus() == null);
}
/**
* @return indicates the type of platform certificate.
*/
public boolean isVersion2() {
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ComponentIdentifierV2{");
sb.append("componentClass=").append(componentClass);
sb.append(", componentManufacturer=").append(getComponentManufacturer()
.getString());
sb.append(", componentModel=").append(getComponentModel().getString());
// Optional not null values
sb.append(", componentSerial=");
if (getComponentSerial() != null) {
sb.append(getComponentSerial().getString());
}
sb.append(", componentRevision=");
if (getComponentRevision() != null) {
sb.append(getComponentRevision().getString());
}
sb.append(", componentManufacturerId=");
if (getComponentManufacturerId() != null) {
sb.append(getComponentManufacturerId().getId());
}
sb.append(", fieldReplaceable=");
if (getFieldReplaceable() != null) {
sb.append(getFieldReplaceable().toString());
}
sb.append(", componentAddress=");
if (getComponentAddress().size() > 0) {
sb.append(getComponentAddress()
.stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
sb.append(", certificateIdentifier=");
if (certificateIdentifier != null) {
sb.append(certificateIdentifier.toString());
}
sb.append(", componentPlatformUri=");
if (componentPlatformUri != null) {
sb.append(componentPlatformUri.toString());
}
sb.append(", status=");
if (attributeStatus != null) {
sb.append(attributeStatus.getValue());
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,119 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import java.util.ArrayList;
import java.util.stream.Collectors;
/**
* Basic class that handle Platform Configuration for the Platform Certificate
* Attribute.
* <pre>
* PlatformConfiguration ::= SEQUENCE {
* componentIdentifier [0] IMPLICIT SEQUENCE(SIZE(1..CONFIGMAX)) OF
* ComponentIdentifier OPTIONAL,
* componentIdentifiersUri [1] IMPLICIT URIReference OPTIONAL
* platformProperties [2] IMPLICIT SEQUENCE(SIZE(1..CONFIGMAX)) OF Properties OPTIONAL,
* platformPropertiesUri [3] IMPLICIT URIReference OPTIONAL }
* </pre>
*/
public class PlatformConfigurationV2 extends PlatformConfiguration {
private static final int COMPONENT_IDENTIFIER = 0;
private static final int COMPONENT_IDENTIFIER_URI = 1;
private static final int PLATFORM_PROPERTIES = 2;
private static final int PLATFORM_PROPERTIES_URI = 3;
/**
* Constructor given the SEQUENCE that contains Platform Configuration.
* @param sequence containing the the Platform Configuration.
* @throws IllegalArgumentException if there was an error on the parsing
*/
public PlatformConfigurationV2(final ASN1Sequence sequence) throws IllegalArgumentException {
//Default values
setComponentIdentifier(new ArrayList<>());
setComponentIdentifierUri(null);
setPlatformProperties(new ArrayList<>());
setPlatformPropertiesUri(null);
for (int i = 0; i < sequence.size(); i++) {
ASN1TaggedObject taggedSequence
= ASN1TaggedObject.getInstance(sequence.getObjectAt(i));
//Set information based on the set tagged
switch (taggedSequence.getTagNo()) {
case COMPONENT_IDENTIFIER:
//Get componentIdentifier
ASN1Sequence componentConfiguration
= ASN1Sequence.getInstance(taggedSequence, false);
//Get and set all the component values
for (int j = 0; j < componentConfiguration.size(); j++) {
//DERSequence with the components
ASN1Sequence component
= ASN1Sequence.getInstance(componentConfiguration.getObjectAt(j));
add(new ComponentIdentifierV2(component));
}
break;
case COMPONENT_IDENTIFIER_URI:
//Get componentIdentifierURI
ASN1Sequence componentUri = ASN1Sequence.getInstance(taggedSequence, false);
//Save Component Identifier URI
setComponentIdentifierUri(new URIReference(componentUri));
break;
case PLATFORM_PROPERTIES:
//Get platformProperties
ASN1Sequence properties = ASN1Sequence.getInstance(taggedSequence, false);
//Get and set all the properties values
for (int j = 0; j < properties.size(); j++) {
//DERSequence with the components
ASN1Sequence property = ASN1Sequence.getInstance(properties.getObjectAt(j));
add(new PlatformPropertyV2(property));
}
break;
case PLATFORM_PROPERTIES_URI:
//Get platformPropertiesURI
ASN1Sequence propertiesUri = ASN1Sequence.getInstance(taggedSequence, false);
//Save properties URI
setPlatformPropertiesUri(new URIReference(propertiesUri));
break;
default:
break;
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("PlatformConfiguration{");
sb.append("componentIdentifier=");
if (getComponentIdentifier().size() > 0) {
sb.append(getComponentIdentifier()
.stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
sb.append(", componentIdentifierUri=");
if (getComponentIdentifierUri() != null) {
sb.append(getComponentIdentifierUri().toString());
}
sb.append(", platformProperties=");
if (getPlatformProperties().size() > 0) {
sb.append(getPlatformProperties()
.stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
sb.append(", platformPropertiesUri=");
if (getPlatformPropertiesUri() != null) {
sb.append(getPlatformPropertiesUri().toString());
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,100 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformProperty;
import lombok.Getter;
import lombok.Setter;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERUTF8String;
/**
*
* Basic class that handles a single property for the platform configuration.
* <pre>
* Properties ::= SEQUENCE {
* propertyName UTF8String (SIZE (1..STRMAX)),
* propertyValue UTF8String (SIZE (1..STRMAX),
* status [0] IMPLICIT AttributeStatus OPTIONAL }
*
* </pre>
*/
public class PlatformPropertyV2 extends PlatformProperty {
@Getter
@Setter
private AttributeStatus attributeStatus;
/**
* Default constructor.
*/
public PlatformPropertyV2() {
super();
this.attributeStatus = AttributeStatus.EMPTY_STATUS;
}
/**
* Constructor given the name and value for the platform property.
*
* @param propertyName string containing the property name
* @param propertyValue string containing the property value
* @param attributeStatus enumerated object with the status of the property
*/
public PlatformPropertyV2(final DERUTF8String propertyName, final DERUTF8String propertyValue,
final AttributeStatus attributeStatus) {
super(propertyName, propertyValue);
this.attributeStatus = attributeStatus;
}
/**
* Constructor given the SEQUENCE that contains the name and value for the
* platform property.
*
* @param sequence containing the name and value of the platform property
* @throws IllegalArgumentException if there was an error on the parsing
*/
public PlatformPropertyV2(final ASN1Sequence sequence) throws IllegalArgumentException {
// Check if the sequence contains the two values required
if (sequence.size() < IDENTIFIER_NUMBER) {
throw new IllegalArgumentException("Platform properties does not contain all "
+ "the required fields.");
}
setPropertyName(DERUTF8String.getInstance(sequence.getObjectAt(0)));
setPropertyValue(DERUTF8String.getInstance(sequence.getObjectAt(1)));
// optional value which is a placeholder for now
if (sequence.size() > IDENTIFIER_NUMBER
&& sequence.getObjectAt(2) instanceof ASN1Enumerated) {
ASN1Enumerated enumerated = ASN1Enumerated.getInstance(sequence.getObjectAt(2));
this.attributeStatus = AttributeStatus.values()[enumerated.getValue().intValue()];
}
}
/**
* @return true if the property has been modified.
*/
public final boolean isModified() {
return getAttributeStatus() == AttributeStatus.MODIFIED;
}
/**
* @return true if the property has been removed.
*/
public final boolean isRemoved() {
return getAttributeStatus() != AttributeStatus.REMOVED;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("PlatformPropertyV2{");
sb.append("PropertyName=").append(getPropertyName().getString());
sb.append(", propertyValue=").append(getPropertyValue().getString());
if (attributeStatus != null) {
sb.append(", attributeStatus=").append(attributeStatus.toString());
}
sb.append("}");
return sb.toString();
}
}

View File

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

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

@ -0,0 +1,60 @@
package hirs.attestationca.persist.entity.userdefined.info;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.utils.StringValidator;
import jakarta.persistence.Column;
import jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import java.io.Serializable;
/**
* Used for representing the firmware info of a device, such as the BIOS information.
*/
@ToString
@EqualsAndHashCode
@Getter
public class FirmwareInfo implements Serializable {
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private final String biosVendor;
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private final String biosVersion;
@XmlElement
@Column(length = DeviceInfoReport.SHORT_STRING_LENGTH, nullable = false)
private final String biosReleaseDate;
/**
* Constructor used to create a populated firmware info object.
*
* @param biosVendor String bios vendor name, i.e. Dell Inc.
* @param biosVersion String bios version info, i.e. A11
* @param biosReleaseDate String bios release date info, i.e. 03/12/2013
*/
public FirmwareInfo(final String biosVendor, final String biosVersion,
final String biosReleaseDate) {
this.biosVendor = StringValidator.check(biosVendor, "biosVendor")
.notBlank().maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
this.biosVersion = StringValidator.check(biosVersion, "biosVersion")
.notBlank().maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
this.biosReleaseDate = StringValidator.check(biosReleaseDate, "biosReleaseDate")
.notBlank().maxLength(DeviceInfoReport.SHORT_STRING_LENGTH).getValue();
}
/**
* Default constructor, useful for hibernate and marshalling and unmarshalling.
*/
public FirmwareInfo() {
this(DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED);
}
}

View File

@ -0,0 +1,122 @@
package hirs.attestationca.persist.entity.userdefined.info;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.utils.StringValidator;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
/**
* Used for representing the hardware info of a device.
*/
@EqualsAndHashCode
@Getter
@Embeddable
public class HardwareInfo implements Serializable {
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private String manufacturer = DeviceInfoReport.NOT_SPECIFIED;
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private String productName = DeviceInfoReport.NOT_SPECIFIED;
@XmlElement
@Column(length = DeviceInfoReport.MED_STRING_LENGTH, nullable = false)
private String version = DeviceInfoReport.NOT_SPECIFIED;
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private String systemSerialNumber = DeviceInfoReport.NOT_SPECIFIED;
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private String chassisSerialNumber = DeviceInfoReport.NOT_SPECIFIED;
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private String baseboardSerialNumber = DeviceInfoReport.NOT_SPECIFIED;
/**
* Constructor used to create a populated firmware info object.
*
* @param manufacturer String manufacturer name
* @param productName String product name info
* @param version String bios release date info
* @param systemSerialNumber String device serial number
* @param chassisSerialNumber String device chassis serial number
* @param baseboardSerialNumber String device baseboard serial number
*/
public HardwareInfo(
final String manufacturer,
final String productName,
final String version,
final String systemSerialNumber,
final String chassisSerialNumber,
final String baseboardSerialNumber) {
if (!StringUtils.isBlank(manufacturer)) {
this.manufacturer = StringValidator.check(manufacturer, "manufacturer")
.maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
}
if (!StringUtils.isBlank(productName)) {
this.productName = StringValidator.check(productName, "productName")
.maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
}
if (!StringUtils.isBlank(version)) {
this.version = StringValidator.check(version, "version")
.maxLength(DeviceInfoReport.MED_STRING_LENGTH).getValue();
}
if (!StringUtils.isBlank(systemSerialNumber)) {
this.systemSerialNumber = StringValidator.check(systemSerialNumber,
"systemSerialNumber")
.maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
}
if (!StringUtils.isBlank(chassisSerialNumber)) {
this.chassisSerialNumber = StringValidator.check(chassisSerialNumber,
"chassisSerialNumber")
.maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
}
if (!StringUtils.isBlank(baseboardSerialNumber)) {
this.baseboardSerialNumber = StringValidator.check(
baseboardSerialNumber, "baseboardSerialNumber")
.maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
}
}
/**
* Default constructor, useful for hibernate and marshalling and unmarshalling.
*/
public HardwareInfo() {
this(
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED
);
}
@Override
public String toString() {
return "HardwareInfo{"
+ "manufacturer='" + manufacturer + '\''
+ ", productName='" + productName + '\''
+ ", version='" + version + '\''
+ ", systemSerialNumber='" + systemSerialNumber + '\''
+ ", chassisSerialNumber='" + chassisSerialNumber + '\''
+ ", baseboardSerialNumber='" + baseboardSerialNumber + '\''
+ '}';
}
}

View File

@ -0,0 +1,111 @@
package hirs.attestationca.persist.entity.userdefined.info;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serializable;
import java.net.InetAddress;
/**
* This class is used to represent the network info of a device.
*/
@EqualsAndHashCode
@Embeddable
public class NetworkInfo implements Serializable {
private static final Logger LOGGER = LogManager
.getLogger(NetworkInfo.class);
private static final int NUM_MAC_ADDRESS_BYTES = 6;
@XmlElement
@Setter
@Getter
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = true)
private String hostname;
@XmlElement
// @XmlJavaTypeAdapter(value = InetAddressXmlAdapter.class)
@Setter
@Getter
@Column(length = DeviceInfoReport.SHORT_STRING_LENGTH, nullable = true)
// @Convert(converter = hirs.attestationca.persist.type.InetAddressType.class)
private InetAddress ipAddress;
@XmlElement
@Column(length = NUM_MAC_ADDRESS_BYTES, nullable = true)
@SuppressWarnings("checkstyle:magicnumber")
private byte[] macAddress;
/**
* Constructor used to create a NetworkInfo object.
*
* @param hostname
* String representing the hostname information for the device,
* can be null if hostname unknown
* @param ipAddress
* InetAddress object representing the IP address for the device,
* can be null if IP address unknown
* @param macAddress
* byte array representing the MAC address for the device, can be
* null if MAC address is unknown
*/
public NetworkInfo(final String hostname, final InetAddress ipAddress,
final byte[] macAddress) {
setHostname(hostname);
setIpAddress(ipAddress);
setMacAddress(macAddress);
}
/**
* Default constructor necessary for marshalling/unmarshalling XML objects.
*/
protected NetworkInfo() {
this.hostname = null;
this.ipAddress = null;
this.macAddress = null;
}
/**
* Used to retrieve the MAC address of the device.
*
* @return a String representing the MAC address, may return null if no
* value is set
*/
public final byte[] getMacAddress() {
if (macAddress == null) {
return null;
} else {
return macAddress.clone();
}
}
private void setMacAddress(final byte[] macAddress) {
StringBuilder sb;
if (macAddress == null) {
sb = null;
} else {
if (macAddress.length != NUM_MAC_ADDRESS_BYTES) {
LOGGER.error(
"MAC address is only {} bytes, must be {} bytes or "
+ "null", macAddress.length,
NUM_MAC_ADDRESS_BYTES);
throw new IllegalArgumentException(
"MAC address is invalid size");
}
sb = new StringBuilder();
for (byte b : macAddress) {
sb.append(String.format("%02X ", b));
}
}
LOGGER.debug("setting MAC address to: {}", sb);
this.macAddress = macAddress;
}
}

View File

@ -0,0 +1,99 @@
package hirs.attestationca.persist.entity.userdefined.info;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.utils.StringValidator;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serializable;
/**
* This class is used to represent the OS info of a device.
*/
@EqualsAndHashCode
@ToString
@Getter
@Embeddable
public class OSInfo implements Serializable {
private static final Logger LOGGER = LogManager.getLogger(OSInfo.class);
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private final String osName;
@XmlElement
@Column(length = DeviceInfoReport.LONG_STRING_LENGTH, nullable = false)
private final String osVersion;
@XmlElement
@Column(length = DeviceInfoReport.SHORT_STRING_LENGTH, nullable = false)
private final String osArch;
@XmlElement
@Column(length = DeviceInfoReport.SHORT_STRING_LENGTH, nullable = true)
private final String distribution;
@XmlElement
@Column(length = DeviceInfoReport.SHORT_STRING_LENGTH, nullable = true)
private final String distributionRelease;
/**
* Constructor used to create an OSInfo object. This constructor takes an OS
* name (Linux | Mac OS X | Windows 7), an OS version (i.e.
* 3.10.0-123.el7.x86_64), OS architecture (x86_64), distribution (CentOS |
* Fedora), and distribution release (7.0.1406). Distribution only makes
* sense for Linux, so distribution and distributionRelease may be null.
*
* @param osName
* String OS name (Linux | Mac OS X | Windows 7)
* @param osVersion
* String OS version (i.e. 3.10.0-123.el7.x86_64)
* @param osArch
* String OS architecture (x86_64)
* @param distribution
* String distribution (CentOS | Fedora)
* @param distributionRelease
* String distribution release (7.0.1406)
*/
public OSInfo(final String osName, final String osVersion,
final String osArch, final String distribution,
final String distributionRelease) {
LOGGER.debug("setting OS name information to: {}", osName);
this.osName = StringValidator.check(osName, "osName")
.notNull().maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
LOGGER.debug("setting OS version information to: {}", osVersion);
this.osVersion = StringValidator.check(osVersion, "osVersion")
.notNull().maxLength(DeviceInfoReport.LONG_STRING_LENGTH).getValue();
LOGGER.debug("setting OS arch information to: {}", osArch);
this.osArch = StringValidator.check(osArch, "osArch")
.notNull().maxLength(DeviceInfoReport.SHORT_STRING_LENGTH).getValue();
LOGGER.debug("setting OS distribution information to: {}", distribution);
this.distribution = StringValidator.check(distribution, "distribution")
.maxLength(DeviceInfoReport.SHORT_STRING_LENGTH).getValue();
LOGGER.debug("setting OS distribution release information to: {}",
distributionRelease);
this.distributionRelease = StringValidator.check(distributionRelease, "distributionRelease")
.maxLength(DeviceInfoReport.SHORT_STRING_LENGTH).getValue();
}
/**
* Default constructor necessary for marshalling/unmarshalling XML objects.
*/
public OSInfo() {
this(DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED);
}
}

View File

@ -0,0 +1,66 @@
package hirs.attestationca.persist.entity.userdefined.info;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.utils.StringValidator;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import java.io.Serializable;
@Getter
@EqualsAndHashCode
@Embeddable
public class RIMInfo implements Serializable {
@XmlElement
@Column(length = DeviceInfoReport.MED_STRING_LENGTH, nullable = false)
private final String rimManufacturer;
@XmlElement
@Column(length = DeviceInfoReport.MED_STRING_LENGTH, nullable = false)
private final String model;
@XmlElement
@Column(length = DeviceInfoReport.MED_STRING_LENGTH, nullable = false)
private final String fileHash;
@XmlElement
@Column(length = DeviceInfoReport.MED_STRING_LENGTH, nullable = false)
private final String pcrHash;
/**
* Constructor for the initial values of the class.
* @param rimManufacturer string of the rimManufacturer
* @param model string of the model
* @param fileHash string of the file hash
* @param pcrHash string of the pcr hash
*/
public RIMInfo(final String rimManufacturer, final String model,
final String fileHash, final String pcrHash) {
this.rimManufacturer = StringValidator.check(rimManufacturer, "rimManufacturer")
.notBlank().maxLength(DeviceInfoReport.MED_STRING_LENGTH).getValue();
this.model = StringValidator.check(model, "model")
.notBlank().maxLength(DeviceInfoReport.MED_STRING_LENGTH).getValue();
this.fileHash = StringValidator.check(fileHash, "fileHash")
.notBlank().maxLength(DeviceInfoReport.MED_STRING_LENGTH).getValue();
this.pcrHash = StringValidator.check(pcrHash, "pcrHash")
.notBlank().maxLength(DeviceInfoReport.MED_STRING_LENGTH).getValue();
}
/**
* Default no parameter constructor.
*/
public RIMInfo() {
this(DeviceInfoReport.NOT_SPECIFIED, DeviceInfoReport.NOT_SPECIFIED,
DeviceInfoReport.NOT_SPECIFIED, DeviceInfoReport.NOT_SPECIFIED);
}
@Override
public String toString() {
return String.format("%s, %s, %s, %s", rimManufacturer, model,
fileHash, pcrHash);
}
}

View File

@ -0,0 +1,319 @@
package hirs.attestationca.persist.entity.userdefined.info;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.utils.StringValidator;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Lob;
import jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serializable;
import java.security.cert.X509Certificate;
/**
* This class is used to represent the TPM information for a device.
*/
@Getter
@EqualsAndHashCode
@Embeddable
public class TPMInfo implements Serializable {
private static final Logger LOGGER = LogManager.getLogger(TPMInfo.class);
private static final int MAX_BLOB_SIZE = 55535;
@XmlElement
@Column(length = DeviceInfoReport.MED_STRING_LENGTH, nullable = true)
private String tpmMake;
@XmlElement
@Column(nullable = true)
private short tpmVersionMajor;
@XmlElement
@Column(nullable = true)
private short tpmVersionMinor;
@XmlElement
@Column(nullable = true)
private short tpmVersionRevMajor;
@XmlElement
@Column(nullable = true)
private short tpmVersionRevMinor;
@XmlElement
// @XmlJavaTypeAdapter(X509CertificateAdapter.class)
@Lob
// @Type(type = "hirs.attestationca.persist.type.X509CertificateType")
@JsonIgnore
private X509Certificate identityCertificate;
@Column(nullable = true, length = MAX_BLOB_SIZE)
@Lob
private byte[] pcrValues;
@Column(nullable = true, length = MAX_BLOB_SIZE)
@Lob
private byte[] tpmQuoteHash;
@Column(nullable = true, length = MAX_BLOB_SIZE)
@Lob
private byte[] tpmQuoteSignature;
/**
* Constructor used to create a TPMInfo object.
*
* @param tpmMake
* String representing the make information for the TPM,
* NullPointerException thrown if null
* @param tpmVersionMajor
* short representing the major version number for the TPM
* @param tpmVersionMinor
* short representing the minor version number for the TPM
* @param tpmVersionRevMajor
* short representing the major revision number for the TPM
* @param tpmVersionRevMinor
* short representing the minor revision number for the TPM
* @param identityCertificate
* byte array with the value of the identity certificate
* @param pcrValues
* short representing the major revision number for the TPM
* @param tpmQuoteHash
* short representing the minor revision number for the TPM
* @param tpmQuoteSignature
* byte array with the value of the identity certificate
*/
@SuppressWarnings("parameternumber")
public TPMInfo(final String tpmMake, final short tpmVersionMajor,
final short tpmVersionMinor, final short tpmVersionRevMajor,
final short tpmVersionRevMinor,
final X509Certificate identityCertificate, final byte[] pcrValues,
final byte[] tpmQuoteHash, final byte[] tpmQuoteSignature) {
setTPMMake(tpmMake);
setTPMVersionMajor(tpmVersionMajor);
setTPMVersionMinor(tpmVersionMinor);
setTPMVersionRevMajor(tpmVersionRevMajor);
setTPMVersionRevMinor(tpmVersionRevMinor);
setIdentityCertificate(identityCertificate);
setPcrValues(pcrValues);
setTpmQuoteHash(tpmQuoteHash);
setTpmQuoteSignature(tpmQuoteSignature);
}
/**
* Constructor used to create a TPMInfo object without an identity
* certificate.
*
* @param tpmMake
* String representing the make information for the TPM,
* NullPointerException thrown if null
* @param tpmVersionMajor
* short representing the major version number for the TPM
* @param tpmVersionMinor
* short representing the minor version number for the TPM
* @param tpmVersionRevMajor
* short representing the major revision number for the TPM
* @param tpmVersionRevMinor
* short representing the minor revision number for the TPM
* @param pcrValues
* short representing the major revision number for the TPM
* @param tpmQuoteHash
* short representing the minor revision number for the TPM
* @param tpmQuoteSignature
* byte array with the value of the identity certificate
*/
@SuppressWarnings("parameternumber")
public TPMInfo(final String tpmMake, final short tpmVersionMajor,
final short tpmVersionMinor, final short tpmVersionRevMajor,
final short tpmVersionRevMinor, final byte[] pcrValues,
final byte[] tpmQuoteHash, final byte[] tpmQuoteSignature) {
setTPMMake(tpmMake);
setTPMVersionMajor(tpmVersionMajor);
setTPMVersionMinor(tpmVersionMinor);
setTPMVersionRevMajor(tpmVersionRevMajor);
setTPMVersionRevMinor(tpmVersionRevMinor);
setPcrValues(pcrValues);
setTpmQuoteHash(tpmQuoteHash);
setTpmQuoteSignature(tpmQuoteSignature);
}
/**
* Constructor used to create a TPMInfo object without an identity
* certificate.
*
* @param tpmMake
* String representing the make information for the TPM,
* NullPointerException thrown if null
* @param tpmVersionMajor
* short representing the major version number for the TPM
* @param tpmVersionMinor
* short representing the minor version number for the TPM
* @param tpmVersionRevMajor
* short representing the major revision number for the TPM
* @param tpmVersionRevMinor
* short representing the minor revision number for the TPM
*/
public TPMInfo(final String tpmMake, final short tpmVersionMajor,
final short tpmVersionMinor, final short tpmVersionRevMajor,
final short tpmVersionRevMinor) {
this(tpmMake, tpmVersionMajor, tpmVersionMinor, tpmVersionRevMajor,
tpmVersionRevMinor, null,
new byte[0], new byte[0], new byte[0]);
}
/**
* Constructor used to create a TPMInfo object without an identity
* certificate.
*
* @param tpmMake
* String representing the make information for the TPM,
* NullPointerException thrown if null
* @param tpmVersionMajor
* short representing the major version number for the TPM
* @param tpmVersionMinor
* short representing the minor version number for the TPM
* @param tpmVersionRevMajor
* short representing the major revision number for the TPM
* @param tpmVersionRevMinor
* short representing the minor revision number for the TPM
* @param identityCertificate
* byte array with the value of the identity certificate
*/
public TPMInfo(final String tpmMake, final short tpmVersionMajor,
final short tpmVersionMinor, final short tpmVersionRevMajor,
final short tpmVersionRevMinor,
final X509Certificate identityCertificate) {
this(tpmMake, tpmVersionMajor, tpmVersionMinor, tpmVersionRevMajor,
tpmVersionRevMinor, identityCertificate,
new byte[0], new byte[0], new byte[0]);
}
/**
* Default constructor used for marshalling/unmarshalling XML objects.
*/
public TPMInfo() {
this(DeviceInfoReport.NOT_SPECIFIED,
(short) 0,
(short) 0,
(short) 0,
(short) 0,
new byte[0],
new byte[0],
new byte[0]);
identityCertificate = null;
}
/**
* Getter for the tpmQuote passed up by the client.
* @return a byte blob of quote
*/
public final byte[] getTpmQuoteHash() {
return tpmQuoteHash.clone();
}
/**
* Getter for the quote signature.
* @return a byte blob.
*/
public final byte[] getTpmQuoteSignature() {
return tpmQuoteSignature.clone();
}
/**
* Getter for the pcr values.
* @return a byte blob for the pcrValues.
*/
public final byte[] getPcrValues() {
return pcrValues.clone();
}
private void setTPMMake(final String tpmMake) {
LOGGER.debug("setting TPM make info: {}", tpmMake);
this.tpmMake = StringValidator.check(tpmMake, "tpmMake")
.notNull().maxLength(DeviceInfoReport.MED_STRING_LENGTH).getValue();
}
private void setTPMVersionMajor(final short tpmVersionMajor) {
if (tpmVersionMajor < 0) {
LOGGER.error("TPM major version number cannot be negative: {}",
tpmVersionMajor);
throw new IllegalArgumentException(
"negative TPM major version number");
}
LOGGER.debug("setting TPM major version number: {}", tpmVersionMajor);
this.tpmVersionMajor = tpmVersionMajor;
}
private void setTPMVersionMinor(final short tpmVersionMinor) {
if (tpmVersionMinor < 0) {
LOGGER.error("TPM minor version number cannot be negative: {}",
tpmVersionMinor);
throw new IllegalArgumentException(
"negative TPM minor version number");
}
LOGGER.debug("setting TPM minor version number: {}", tpmVersionMinor);
this.tpmVersionMinor = tpmVersionMinor;
}
private void setTPMVersionRevMajor(final short tpmVersionRevMajor) {
if (tpmVersionRevMajor < 0) {
LOGGER.error("TPM major revision number cannot be negative: {}",
tpmVersionRevMajor);
throw new IllegalArgumentException(
"negative TPM major revision number");
}
LOGGER.debug("setting TPM major revision version number: {}",
tpmVersionRevMajor);
this.tpmVersionRevMajor = tpmVersionRevMajor;
}
private void setTPMVersionRevMinor(final short tpmVersionRevMinor) {
if (tpmVersionRevMinor < 0) {
LOGGER.error("TPM minor revision number cannot be negative: {}",
tpmVersionRevMinor);
throw new IllegalArgumentException(
"negative TPM minor revision number");
}
LOGGER.debug("setting TPM minor revision version number: {}",
tpmVersionRevMinor);
this.tpmVersionRevMinor = tpmVersionRevMinor;
}
private void setIdentityCertificate(
final X509Certificate identityCertificate) {
if (identityCertificate == null) {
LOGGER.error("identity certificate cannot be null");
throw new NullPointerException("identityCertificate");
}
LOGGER.debug("setting identity certificate");
this.identityCertificate = identityCertificate;
}
private void setPcrValues(final byte[] pcrValues) {
if (pcrValues == null) {
this.pcrValues = new byte[0];
} else {
this.pcrValues = pcrValues.clone();
}
}
private void setTpmQuoteHash(final byte[] tpmQuoteHash) {
if (tpmQuoteHash == null) {
this.tpmQuoteHash = new byte[0];
} else {
this.tpmQuoteHash = tpmQuoteHash.clone();
}
}
private void setTpmQuoteSignature(final byte[] tpmQuoteSignature) {
if (tpmQuoteSignature == null) {
this.tpmQuoteSignature = new byte[0];
} else {
this.tpmQuoteSignature = tpmQuoteSignature.clone();
}
}
}

View File

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

View File

@ -0,0 +1,289 @@
package hirs.attestationca.persist.entity.userdefined.report;
import hirs.attestationca.persist.entity.userdefined.Report;
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.utils.VersionHelper;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Transient;
import lombok.Getter;
import lombok.Setter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serializable;
/**
* A <code>DeviceInfoReport</code> is a <code>Report</code> used to transfer the
* information about the device. This <code>Report</code> includes the network,
* OS, and TPM information.
*/
@Entity
public class DeviceInfoReport extends Report implements Serializable {
private static final Logger LOGGER = LogManager.getLogger(DeviceInfoReport.class);
/**
* A variable used to describe unavailable hardware, firmware, or OS info.
*/
public static final String NOT_SPECIFIED = "Not Specified";
/**
* Constant variable representing the various Short sized strings.
*/
public static final int SHORT_STRING_LENGTH = 32;
/**
* Constant variable representing the various Medium sized strings.
*/
public static final int MED_STRING_LENGTH = 64;
/**
* Constant variable representing the various Long sized strings.
*/
public static final int LONG_STRING_LENGTH = 255;
@Embedded
private NetworkInfo networkInfo;
@Embedded
private OSInfo osInfo;
@Embedded
private FirmwareInfo firmwareInfo;
@Embedded
private HardwareInfo hardwareInfo;
@Embedded
private TPMInfo tpmInfo;
@Getter
@Column(nullable = false)
private String clientApplicationVersion;
@Getter
@Setter
@Transient
private String paccorOutputString;
/**
* Default constructor necessary for marshalling/unmarshalling.
*/
public DeviceInfoReport() {
/* do nothing */
}
/**
* Constructor used to create a <code>DeviceInfoReport</code>. The
* information cannot be changed after the <code>DeviceInfoReport</code> is
* created.
*
* @param networkInfo
* NetworkInfo object, cannot be null
* @param osInfo
* OSInfo object, cannot be null
* @param firmwareInfo
* FirmwareInfo object, cannot be null
* @param hardwareInfo
* HardwareInfo object, cannot be null
* @param tpmInfo
* TPMInfo object, may be null if a TPM is not available on the
* device
*/
public DeviceInfoReport(final NetworkInfo networkInfo, final OSInfo osInfo,
final FirmwareInfo firmwareInfo, final HardwareInfo hardwareInfo,
final TPMInfo tpmInfo) {
this(networkInfo, osInfo, firmwareInfo, hardwareInfo, tpmInfo, VersionHelper.getVersion());
}
/**
* Constructor used to create a <code>DeviceInfoReport</code>. The
* information cannot be changed after the <code>DeviceInfoReport</code> is
* created.
*
* @param networkInfo
* NetworkInfo object, cannot be null
* @param osInfo
* OSInfo object, cannot be null
* @param firmwareInfo
* FirmwareInfo object, cannot be null
* @param hardwareInfo
* HardwareInfo object, cannot be null
* @param tpmInfo
* TPMInfo object, may be null if a TPM is not available on the
* device
* @param clientApplicationVersion
* string representing the version of the client that submitted this report,
* cannot be null
*/
public DeviceInfoReport(final NetworkInfo networkInfo, final OSInfo osInfo,
final FirmwareInfo firmwareInfo, final HardwareInfo hardwareInfo,
final TPMInfo tpmInfo, final String clientApplicationVersion) {
setNetworkInfo(networkInfo);
setOSInfo(osInfo);
setFirmwareInfo(firmwareInfo);
setHardwareInfo(hardwareInfo);
setTPMInfo(tpmInfo);
this.clientApplicationVersion = clientApplicationVersion;
}
/**
* Retrieves the NetworkInfo for this <code>DeviceInfoReport</code>.
*
* @return networkInfo
*/
public NetworkInfo getNetworkInfo() {
/*
* Hibernate bug requires this
* https://hibernate.atlassian.net/browse/HHH-7610
* without null may be returned, which this interface does not support
*/
if (networkInfo == null) {
networkInfo = new NetworkInfo(null, null, null);
}
return networkInfo;
}
/**
* Retrieves the OSInfo for this <code>DeviceInfoReport</code>.
*
* @return osInfo
*/
public OSInfo getOSInfo() {
/*
* Hibernate bug requires this
* https://hibernate.atlassian.net/browse/HHH-7610
* without null may be returned, which this interface does not support
*/
if (osInfo == null) {
osInfo = new OSInfo(NOT_SPECIFIED, NOT_SPECIFIED,
NOT_SPECIFIED, NOT_SPECIFIED, NOT_SPECIFIED);
}
return osInfo;
}
/**
* Retrieves the FirmwareInfo for this <code>DeviceInfoReport</code>.
*
* @return osInfo
*/
public FirmwareInfo getFirmwareInfo() {
/*
* Hibernate bug requires this
* https://hibernate.atlassian.net/browse/HHH-7610
* without null may be returned, which this interface does not support
*/
if (firmwareInfo == null) {
firmwareInfo = new FirmwareInfo(NOT_SPECIFIED,
NOT_SPECIFIED, NOT_SPECIFIED);
}
return firmwareInfo;
}
/**
* Retrieves the OSInfo for this <code>DeviceInfoReport</code>.
*
* @return osInfo
*/
public HardwareInfo getHardwareInfo() {
/*
* Hibernate bug requires this
* https://hibernate.atlassian.net/browse/HHH-7610
* without null may be returned, which this interface does not support
*/
if (hardwareInfo == null) {
hardwareInfo = new HardwareInfo(
NOT_SPECIFIED,
NOT_SPECIFIED,
NOT_SPECIFIED,
NOT_SPECIFIED,
NOT_SPECIFIED,
NOT_SPECIFIED
);
}
return hardwareInfo;
}
/**
* Retrieves the TPMInfo for this <code>DeviceInfoReport</code>. TPMInfo may
* be null if a TPM is not available on the device.
*
* @return tpmInfo, may be null if a TPM is not available on the device
*/
public TPMInfo getTPMInfo() {
return tpmInfo;
}
@Override
public String getReportType() {
return this.getClass().getName();
}
/**
* Searches the given set of TPMBaselines for matching device info fields that
* are determined critical to detecting a kernel update.
* @param tpmBaselines Iterable&lt;TPMBaseline&gt; set of TPMBaseline objects.
* @return True, if one of the TPM baselines in the set has the same kernel-specific
* info as this DeviceInfoReport.
*/
public final boolean matchesKernelInfo() { //final Iterable<TpmWhiteListBaseline> tpmBaselines) {
boolean match = false;
// if (tpmBaselines != null) {
// Retrieve the fields which indicate a kernel update
// final OSInfo kernelOSInfo = getOSInfo();
// perform the search
// for (final TpmWhiteListBaseline baseline : tpmBaselines) {
// final OSInfo baselineOSInfo = baseline.getOSInfo();
// if(baselineOSInfo.getOSName().equalsIgnoreCase(kernelOSInfo.getOSName())
// && baselineOSInfo.getOSVersion().equalsIgnoreCase(kernelOSInfo.getOSVersion())) {
// match = true;
// break;
// }
// }
// }
return match;
}
private void setNetworkInfo(NetworkInfo networkInfo) {
if (networkInfo == null) {
LOGGER.error("NetworkInfo cannot be null");
throw new NullPointerException("network info");
}
this.networkInfo = networkInfo;
}
private void setOSInfo(OSInfo osInfo) {
if (osInfo == null) {
LOGGER.error("OSInfo cannot be null");
throw new NullPointerException("os info");
}
this.osInfo = osInfo;
}
private void setFirmwareInfo(FirmwareInfo firmwareInfo) {
if (firmwareInfo == null) {
LOGGER.error("FirmwareInfo cannot be null");
throw new NullPointerException("firmware info");
}
this.firmwareInfo = firmwareInfo;
}
private void setHardwareInfo(HardwareInfo hardwareInfo) {
if (hardwareInfo == null) {
LOGGER.error("HardwareInfo cannot be null");
throw new NullPointerException("hardware info");
}
this.hardwareInfo = hardwareInfo;
}
private void setTPMInfo(TPMInfo tpmInfo) {
this.tpmInfo = tpmInfo;
}
}

View File

@ -0,0 +1,51 @@
package hirs.attestationca.persist.entity.userdefined.result;
import lombok.Getter;
import lombok.Setter;
/**
* An <code>CertificateValidationResult</code> represents the result of a certificate validation
* operation.
*
*/
@Getter
@Setter
public class CertificateValidationResult {
/**
* Enum used to represent certificate validation status.
*/
public enum CertificateValidationStatus {
/**
* Represents a passing validation.
*/
PASS,
/**
* Represents a failed validation.
*/
FAIL,
/**
* Represents a validation error.
*/
ERROR
}
private CertificateValidationStatus validationStatus;
private String validationResultMessage;
/**
* Sets the certificate validation status and result message.
*
* @param status enum representing the certificate validation status
* @param resultMessage String representing certificate validation message
*/
public final void setCertValidationStatusAndResultMessage(
final CertificateValidationStatus status,
final String resultMessage) {
this.validationStatus = status;
this.validationResultMessage = resultMessage;
}
}

View File

@ -0,0 +1,390 @@
package hirs.attestationca.persist.entity.userdefined.rim;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import hirs.utils.SwidResource;
import hirs.utils.xjc.BaseElement;
import hirs.utils.xjc.Directory;
import hirs.utils.xjc.File;
import hirs.utils.xjc.FilesystemItem;
import hirs.utils.xjc.Link;
import hirs.utils.xjc.Meta;
import hirs.utils.xjc.ResourceCollection;
import hirs.utils.xjc.SoftwareIdentity;
import hirs.utils.xjc.SoftwareMeta;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBElement;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.UnmarshalException;
import jakarta.xml.bind.Unmarshaller;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.xml.namespace.QName;
import javax.xml.validation.Schema;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
/**
*
*/
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class BaseReferenceManifest extends ReferenceManifest {
private static final Logger LOGGER = LogManager.getLogger(BaseReferenceManifest.class);
/**
* Holds the name of the 'base64Hash' field.
*/
public static final String BASE_64_HASH_FIELD = "base64Hash";
private static JAXBContext jaxbContext;
@Column
@JsonIgnore
private String base64Hash = "";
@Column
private String swidName = null;
@Column
private int swidCorpus = 0;
@Column
private String colloquialVersion = null;
@Column
private String product = null;
@Column
private String revision = null;
@Column
private String edition = null;
@Column
private String rimLinkHash = null;
@Column
private String bindingSpec = null;
@Column
private String bindingSpecVersion = null;
@Column
private String platformVersion = null;
@Column
private String payloadType = null;
@Column
private String pcURIGlobal = null;
@Column
private String pcURILocal = null;
private String entityName = null;
private String entityRegId = null;
private String entityRole = null;
private String entityThumbprint = null;
private String linkHref = null;
private String linkRel = null;
/**
* Support constructor for the RIM object.
*
* @param fileName - string representation of the uploaded file.
* @param rimBytes - the file content of the uploaded file.
* @throws IOException - thrown if the file is invalid.
*/
public BaseReferenceManifest(final String fileName, final byte[] rimBytes) throws IOException {
this(rimBytes);
this.setFileName(fileName);
}
/**
* Main constructor for the RIM object. This takes in a byte array of a
* valid swidtag file and parses the information.
*
* @param rimBytes byte array representation of the RIM
* @throws IOException if unable to unmarshal the string
*/
@SuppressWarnings("checkstyle:AvoidInlineConditionals")
public BaseReferenceManifest(final byte[] rimBytes) throws IOException {
super(rimBytes);
this.setRimType(BASE_RIM);
this.setFileName("");
SoftwareIdentity si = validateSwidTag(new ByteArrayInputStream(rimBytes));
MessageDigest digest = null;
this.base64Hash = "";
try {
digest = MessageDigest.getInstance("SHA-256");
this.base64Hash = Base64.getEncoder().encodeToString(
digest.digest(rimBytes));
} catch (NoSuchAlgorithmException noSaEx) {
LOGGER.error(noSaEx);
}
// begin parsing valid swid tag
if (si != null) {
setTagId(si.getTagId());
this.swidName = si.getName();
this.swidCorpus = si.isCorpus() ? 1 : 0;
this.setSwidPatch(si.isPatch());
this.setSwidSupplemental(si.isSupplemental());
this.setSwidVersion(si.getVersion());
if (si.getTagVersion() != null) {
this.setSwidTagVersion(si.getTagVersion().toString());
}
for (Object object : si.getEntityOrEvidenceOrLink()) {
if (object instanceof JAXBElement) {
JAXBElement element = (JAXBElement) object;
String elementName = element.getName().getLocalPart();
switch (elementName) {
case "Meta":
parseSoftwareMeta((SoftwareMeta) element.getValue());
break;
case "Entity":
hirs.utils.xjc.Entity entity
= (hirs.utils.xjc.Entity) element.getValue();
if (entity != null) {
this.entityName = entity.getName();
this.entityRegId = entity.getRegid();
StringBuilder sb = new StringBuilder();
for (String role : entity.getRole()) {
sb.append(String.format("%s%n", role));
}
this.entityRole = sb.toString();
this.entityThumbprint = entity.getThumbprint();
}
break;
case "Link":
Link link
= (Link) element.getValue();
if (link != null) {
this.linkHref = link.getHref();
this.linkRel = link.getRel();
}
break;
case "Payload":
parseResource((ResourceCollection) element.getValue());
break;
case "Signature":
// left blank for a followup issue enhancement
default:
}
}
}
}
}
/**
* This is a helper method that parses the SoftwareMeta tag and stores the
* information in the class fields.
*
* @param softwareMeta The object to parse.
*/
private void parseSoftwareMeta(final SoftwareMeta softwareMeta) {
if (softwareMeta != null) {
for (Map.Entry<QName, String> entry
: softwareMeta.getOtherAttributes().entrySet()) {
switch (entry.getKey().getLocalPart()) {
case "colloquialVersion":
this.colloquialVersion = entry.getValue();
break;
case "product":
this.product = entry.getValue();
break;
case "revision":
this.revision = entry.getValue();
break;
case "edition":
this.edition = entry.getValue();
break;
case "rimLinkHash":
this.rimLinkHash = entry.getValue();
break;
case "bindingSpec":
this.bindingSpec = entry.getValue();
break;
case "bindingSpecVersion":
this.bindingSpecVersion = entry.getValue();
break;
case "platformManufacturerId":
this.setPlatformManufacturerId(entry.getValue());
break;
case "platformModel":
this.setPlatformModel(entry.getValue());
break;
case "platformManufacturerStr":
this.setPlatformManufacturer(entry.getValue());
break;
case "platformVersion":
this.platformVersion = entry.getValue();
break;
case "payloadType":
this.payloadType = entry.getValue();
break;
case "pcURIGlobal":
this.pcURIGlobal = entry.getValue();
break;
case "pcURILocal":
this.pcURILocal = entry.getValue();
break;
default:
}
}
}
}
/**
* This method and code is pulled and adopted from the TCG Tool. Since this
* is taking in an file stored in memory through http, this was changed from
* a file to a stream as the input.
*
* @param fileStream stream of the swidtag file.
* @return a {@link SoftwareIdentity} object
* @throws IOException Thrown by the unmarhsallSwidTag method.
*/
private SoftwareIdentity validateSwidTag(final InputStream fileStream) throws IOException {
JAXBElement jaxbe = unmarshallSwidTag(fileStream);
SoftwareIdentity swidTag = (SoftwareIdentity) jaxbe.getValue();
LOGGER.info(String.format("SWID Tag found: %nname: %s;%ntagId: %s%n%s",
swidTag.getName(), swidTag.getTagId(), SCHEMA_STATEMENT));
return swidTag;
}
/**
* Helper method that is used to parse a specific element of the SwidTag
* based on an already established and stored byte array.
*
* @param elementName string of an xml tag in the file.
* @return the object value of the element, if it exists
*/
private BaseElement getBaseElementFromBytes(final String elementName) {
BaseElement baseElement = null;
if (getRimBytes() != null && elementName != null) {
try {
SoftwareIdentity si = validateSwidTag(new ByteArrayInputStream(getRimBytes()));
JAXBElement element;
for (Object object : si.getEntityOrEvidenceOrLink()) {
if (object instanceof JAXBElement) {
element = (JAXBElement) object;
if (element.getName().getLocalPart().equals(elementName)) {
// found the element
baseElement = (BaseElement) element.getValue();
}
}
}
} catch (IOException ioEx) {
LOGGER.error("Failed to parse Swid Tag bytes.", ioEx);
}
}
return baseElement;
}
/**
* This method unmarshalls the swidtag found at [path] and validates it
* according to the schema.
*
* @param stream to the input swidtag
* @return the SoftwareIdentity element at the root of the swidtag
* @throws IOException if the swidtag cannot be unmarshalled or validated
*/
private JAXBElement unmarshallSwidTag(final InputStream stream) throws IOException {
JAXBElement jaxbe = null;
Schema schema;
try {
schema = ReferenceManifestServiceImpl.getSchemaObject();
if (jaxbContext == null) {
jaxbContext = JAXBContext.newInstance(SCHEMA_PACKAGE);
}
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(schema);
jaxbe = (JAXBElement) unmarshaller.unmarshal(stream);
} catch (UnmarshalException umEx) {
LOGGER.error(String.format("Error validating swidtag file!%n%s%n%s",
umEx.getMessage(), umEx.toString()));
for (StackTraceElement ste : umEx.getStackTrace()) {
LOGGER.error(ste.toString());
}
} catch (IllegalArgumentException iaEx) {
LOGGER.error("Input file empty.");
} catch (JAXBException jaxEx) {
for (StackTraceElement ste : jaxEx.getStackTrace()) {
LOGGER.error(ste.toString());
}
}
if (jaxbe != null) {
return jaxbe;
} else {
throw new IOException("Invalid Base RIM, swidtag format expected.");
}
}
/**
* Default method for parsing the payload element.
*
* @return a collection of payload objects.
*/
public final List<SwidResource> parseResource() {
return parseResource((ResourceCollection) this.getBaseElementFromBytes("Payload"));
}
/**
* This method parses the payload method of a {@link ResourceCollection}.
*
* @param rc Resource Collection object.
* @return a collection of payload objects.
*/
public final List<SwidResource> parseResource(final ResourceCollection rc) {
List<SwidResource> resources = new ArrayList<>();
try {
if (rc != null) {
for (Meta meta : rc.getDirectoryOrFileOrProcess()) {
if (meta != null) {
if (meta instanceof Directory) {
Directory directory = (Directory) meta;
for (FilesystemItem fsi : directory.getDirectoryOrFile()) {
if (fsi != null) {
resources.add(new SwidResource(
(File) fsi, null));
}
}
} else if (meta instanceof File) {
resources.add(new SwidResource((File) meta, null));
}
}
}
}
} catch (ClassCastException ccEx) {
LOGGER.error(ccEx);
LOGGER.error("At this time, the code does not support the "
+ "particular formatting of this SwidTag's Payload.");
}
return resources;
}
@Override
public String toString() {
return String.format("ReferenceManifest{swidName=%s,"
+ "platformManufacturer=%s,"
+ " platformModel=%s,"
+ "tagId=%s, rimHash=%s}",
swidName, this.getPlatformManufacturer(),
this.getPlatformModel(), getTagId(), this.getBase64Hash());
}
}

View File

@ -0,0 +1,64 @@
package hirs.attestationca.persist.entity.userdefined.rim;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.enums.AppraisalStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import lombok.Getter;
import lombok.Setter;
import java.io.IOException;
/**
* Sub class that will just focus on PCR Values and Events.
* Similar to {@link SupportReferenceManifest}
* however this is the live log from the client.
*/
@Entity
public class EventLogMeasurements extends ReferenceManifest {
@Column
@JsonIgnore
@Getter @Setter
private int pcrHash = 0;
@Enumerated(EnumType.STRING)
@Getter @Setter
private AppraisalStatus.Status overallValidationResult = AppraisalStatus.Status.FAIL;
/**
* Support constructor for the RIM object.
*
* @param rimBytes byte array representation of the RIM
* @throws java.io.IOException if unable to unmarshal the string
*/
public EventLogMeasurements(final byte[] rimBytes) throws IOException {
this("blank.measurement", rimBytes);
}
/**
* Support constructor for the RIM object.
*
* @param fileName - string representation of the uploaded file.
* @param rimBytes byte array representation of the RIM
* @throws java.io.IOException if unable to unmarshal the string
*/
public EventLogMeasurements(final String fileName,
final byte[] rimBytes) throws IOException {
super(rimBytes);
this.setFileName(fileName);
this.archive("Event Log Measurement");
this.setRimType(MEASUREMENT_RIM);
this.pcrHash = 0;
}
/**
* Default constructor necessary for Hibernate.
*/
protected EventLogMeasurements() {
super();
this.pcrHash = 0;
}
}

View File

@ -0,0 +1,114 @@
package hirs.attestationca.persist.entity.userdefined.rim;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
* Sub class that will just focus on PCR Values and Events.
*/
@Log4j2
@Getter
@Setter
@Entity
public class SupportReferenceManifest extends ReferenceManifest {
@Column
@JsonIgnore
private int pcrHash = 0;
@Column
private boolean updated = false;
@Column
private boolean processed = false;
/**
* Main constructor for the RIM object. This takes in a byte array of a
* valid swidtag file and parses the information.
*
* @param fileName - string representation of the uploaded file.
* @param rimBytes byte array representation of the RIM
* @throws IOException if unable to unmarshal the string
*/
public SupportReferenceManifest(final String fileName,
final byte[] rimBytes) throws IOException {
super(rimBytes);
this.setFileName(fileName);
this.setRimType(SUPPORT_RIM);
this.pcrHash = 0;
}
/**
* Main constructor for the RIM object. This takes in a byte array of a
* valid swidtag file and parses the information.
*
* @param rimBytes byte array representation of the RIM
* @throws IOException if unable to unmarshal the string
*/
public SupportReferenceManifest(final byte[] rimBytes) throws IOException {
this("blank.rimel", rimBytes);
}
/**
* Default constructor necessary for Hibernate.
*/
protected SupportReferenceManifest() {
super();
this.pcrHash = 0;
}
/**
* Getter method for the expected PCR values contained within the support
* RIM.
* @return a string array of the pcr values.
*/
public String[] getExpectedPCRList() {
try {
TCGEventLog logProcessor = new TCGEventLog(this.getRimBytes());
this.pcrHash = Arrays.hashCode(logProcessor.getExpectedPCRValues());
return logProcessor.getExpectedPCRValues();
} catch (CertificateException cEx) {
log.error(cEx);
} catch (NoSuchAlgorithmException noSaEx) {
log.error(noSaEx);
} catch (IOException ioEx) {
log.error(ioEx);
}
return new String[0];
}
/**
* Getter method for the event log that should be present in the support RIM.
*
* @return list of TPM PCR Events for display
*/
public Collection<TpmPcrEvent> getEventLog() {
TCGEventLog logProcessor = null;
try {
logProcessor = new TCGEventLog(this.getRimBytes());
return logProcessor.getEventList();
} catch (CertificateException cEx) {
log.error(cEx);
} catch (NoSuchAlgorithmException noSaEx) {
log.error(noSaEx);
} catch (IOException ioEx) {
log.error(ioEx);
}
return new ArrayList<>();
}
}

View File

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

View File

@ -0,0 +1,106 @@
package hirs.attestationca.persist.enums;
/**
* Class to capture appraisal results and corresponding messages.
*/
public class AppraisalStatus {
/**
* Enum used to represent appraisal status.
*/
public enum Status {
/**
* Represents a passing appraisal.
*/
PASS,
/**
* Represents a failed appraisal.
*/
FAIL,
/**
* Represents an appraisal generation error.
*/
ERROR,
/**
* Represents an unknown appraisal result.
*/
UNKNOWN
}
private Status appStatus;
private String message;
private String additionalInfo;
/**
* Default constructor. Set appraisal status and description.
* @param appStatus status of appraisal
* @param message description of result
*/
public AppraisalStatus(final Status appStatus, final String message) {
this(appStatus, message, "");
}
/**
* Default constructor. Set appraisal status and description.
* @param appStatus status of appraisal
* @param message description of result
* @param additionalInfo any additional information needed to
* be passed on
*/
public AppraisalStatus(final Status appStatus, final String message,
final String additionalInfo) {
this.appStatus = appStatus;
this.message = message;
this.additionalInfo = additionalInfo;
}
/**
* Get appraisal status.
* @return appraisal status
*/
public Status getAppStatus() {
return appStatus;
}
/**
* Set appraisal status.
* @param appStatus new status
*/
public void setAppStatus(final Status appStatus) {
this.appStatus = appStatus;
}
/**
* Get appraisal description message.
* @return appraisal description message
*/
public String getMessage() {
return message;
}
/**
* Set appraisal description message.
* @param message appraisal description message
*/
public void setMessage(final String message) {
this.message = message;
}
/**
* Getter for additional information during validation.
* @return string of additional information
*/
public String getAdditionalInfo() {
return additionalInfo;
}
/**
* Setter for any additional information.
* @param additionalInfo the string of additional information
*/
public void setAdditionalInfo(final String additionalInfo) {
this.additionalInfo = additionalInfo;
}
}

View File

@ -0,0 +1,57 @@
package hirs.attestationca.persist.enums;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* <code>HealthStatus</code> is used to represent the health of a device.
*/
public enum HealthStatus {
/**
* The trusted state, no issues with the device.
*/
TRUSTED("trusted"),
/**
* The untrusted state, there is a problem with the device.
*/
UNTRUSTED("untrusted"),
/**
* A state for when the health has not been calculated yet.
*/
UNKNOWN("unknown");
private String healthStatus;
/**
* Creates a new <code>HealthStatus</code> object given a String.
*
* @param healthStatus
* "trusted", "untrusted", or "unknown"
*/
HealthStatus(final String healthStatus) {
this.healthStatus = healthStatus;
}
/**
* Returns the health status.
*
* @return the status
*/
public String getStatus() {
return this.healthStatus;
}
@Override
public String toString() {
return getStatus();
}
public static boolean isValidStatus(final String healthStatus) {
return Arrays.stream(HealthStatus.values())
.map(HealthStatus::name)
.collect(Collectors.toSet())
.contains(healthStatus);
}
}

View File

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

View File

@ -0,0 +1,20 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CertificateServiceImpl {
@Autowired(required = false)
private EntityManager entityManager;
@Autowired
private CertificateRepository repository;
private void saveCertificate(Certificate certificate) {
repository.save(certificate);
}
}

View File

@ -0,0 +1,15 @@
package hirs.attestationca.persist.service;
public class DbServiceImpl {
/**
* The default maximum number of retries to attempt a database transaction.
*/
public static final int DEFAULT_MAX_RETRY_ATTEMPTS = 10;
/*
* The default number of milliseconds to wait before retrying a database transaction.
*/
private static final long DEFAULT_RETRY_WAIT_TIME_MS = 3000;
// structure for retrying methods in the database
// private RetryTemplate retryTemplate;
}

View File

@ -0,0 +1,4 @@
package hirs.attestationca.persist.service;
public interface DefaultService {
}

View File

@ -0,0 +1,32 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.userdefined.Device;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* https://github.com/darrachequesne/spring-data-jpa-datatables
*/
@Service
public class DeviceServiceImpl {
@Autowired(required = false)
private EntityManager entityManager;
@Autowired
private DeviceRepository deviceRepository;
public void saveDevice(Device device) {
this.deviceRepository.save(device);
}
public void saveDevices(List<Device> devices) {
for (Device device : devices) {
this.deviceRepository.save(device);
}
}
}

View File

@ -0,0 +1,70 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import jakarta.persistence.EntityManager;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.xml.sax.SAXException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.IOException;
import java.io.InputStream;
@Log4j2
@Service
public class ReferenceManifestServiceImpl {
/**
* The variable that establishes a schema factory for xml processing.
*/
public static final SchemaFactory SCHEMA_FACTORY
= SchemaFactory.newInstance(ReferenceManifest.SCHEMA_LANGUAGE);
@Autowired(required = false)
private EntityManager entityManager;
@Autowired
private ReferenceManifestRepository repository;
private static Schema schema;
public ReferenceManifestServiceImpl() {
getSchemaObject();
}
/**
* This method sets the xml schema for processing RIMs.
*
* @return the schema
*/
public static final Schema getSchemaObject() {
if (schema == null) {
InputStream is = null;
try {
is = ReferenceManifest.class
.getClassLoader()
.getResourceAsStream(ReferenceManifest.SCHEMA_URL);
schema = SCHEMA_FACTORY.newSchema(new StreamSource(is));
} catch (SAXException saxEx) {
log.error(String.format("Error setting schema for validation!%n%s",
saxEx.getMessage()));
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioEx) {
log.error(String.format("Error closing input stream%n%s",
ioEx.getMessage()));
}
} else {
log.error("Input stream variable is null");
}
}
}
return schema;
}
}

View File

@ -0,0 +1,41 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.manager.SettingsRepository;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SettingsServiceImpl {
@Autowired(required = false)
private EntityManager entityManager;
@Autowired
private SettingsRepository repository;
public SupplyChainSettings updateSettings(SupplyChainSettings settings) {
SupplyChainSettings existing = repository.findByName(settings.getName());
if (existing != null) {
settings.setId(existing.getId());
}
return repository.save(settings);
}
public void saveSettings(SupplyChainSettings settings) {
repository.save(settings);
}
public SupplyChainSettings getByName(String name) {
if (name == null) {
return null;
}
return repository.findByName(name);
}
// public Policy getDefaultPolicy(Appraiser appraiser) {
// return repository.findByAppraiser(appraiser);
// }
}

View File

@ -0,0 +1,190 @@
package hirs.attestationca.persist.type;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Objects;
/**
* This is a class for persisting <code>InetAddress</code> objects via
* Hibernate. This class provides the mapping from <code>InetAddress</code> to
* Hibernate commands to JDBC.
*/
@NoArgsConstructor(access = AccessLevel.PUBLIC)
public final class InetAddressType implements UserType {
/**
* Returns varchar type.
*
* @return varchar type
*/
@Override
public int getSqlType() {
return Types.VARCHAR;
}
/**
* Returns the <code>InetAddress</code> class.
*
* @return <code>InetAddress</code> class
*/
@Override
public Class<InetAddress> returnedClass() {
return InetAddress.class;
}
/**
* Compares x and y using {@link Objects#equals(Object, Object)}.
*
* @param x x
* @param y y
* @return value from equals call
*/
@Override
public boolean equals(final Object x, final Object y) {
return Objects.equals(x, y);
}
/**
* Returns the hash code of x, which will be the same as from
* <code>InetAddress</code>.
*
* @param x x
* @return hash value of x
*/
@Override
public int hashCode(final Object x) {
assert x != null;
return x.hashCode();
}
/**
* Converts the IP address that is stored as a <code>String</code> and
* converts it to an <code>InetAddress</code>.
*
* @param rs
* result set
* @param index
* column names
* @param session
* session
* @param owner
* owner
* @return InetAddress of String
* @throws HibernateException
* if unable to convert the String to an InetAddress
* @throws SQLException
* if unable to retrieve the String from the result set
*/
@Override
public Object nullSafeGet(final ResultSet rs, final int index,
final SharedSessionContractImplementor session, final Object owner)
throws HibernateException, SQLException {
final String ip = rs.getString(index);
if (ip == null) {
return null;
}
try {
return InetAddress.getByName(ip);
} catch (UnknownHostException e) {
final String msg = String.format("unable to convert ip address: %s", ip);
throw new HibernateException(msg, e);
}
}
/**
* Converts the <code>InetAddress</code> <code>value</code> to a
* <code>String</code> and stores it in the database.
*
* @param st prepared statement
* @param value InetAddress
* @param index index
* @param session session
* @throws SQLException if unable to set the value in the result set
*/
@Override
public void nullSafeSet(final PreparedStatement st, final Object value,
final int index, final SharedSessionContractImplementor session)
throws SQLException {
if (value == null) {
st.setString(index, null);
} else {
final InetAddress address = (InetAddress) value;
final String ip = address.getHostAddress();
st.setString(index, ip);
}
}
/**
* Returns <code>value</code> since <code>InetAddress</code> is immutable.
*
* @param value value
* @return value
* @throws HibernateException will never be thrown
*/
@Override
public Object deepCopy(final Object value) throws HibernateException {
return value;
}
/**
* Returns false because <code>InetAddress</code> is immutable.
*
* @return false
*/
@Override
public boolean isMutable() {
return false;
}
/**
* Returns <code>value</code> because <code>InetAddress</code> is
* immutable.
*
* @param value value
* @return value
*/
@Override
public Serializable disassemble(final Object value) {
return (Serializable) value;
}
/**
* Returns <code>cached</code> because <code>InetAddress</code> is
* immutable.
*
* @param cached cached
* @param owner owner
* @return cached
*/
@Override
public Object assemble(final Serializable cached, final Object owner) {
return cached;
}
/**
* Returns the <code>original</code> because <code>InetAddress</code> is
* immutable.
*
* @param original original
* @param target target
* @param owner owner
* @return original
*/
@Override
public Object replace(final Object original, final Object target,
final Object owner) {
return original;
}
}

View File

@ -0,0 +1,203 @@
package hirs.attestationca.persist.type;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;
import javax.sql.rowset.serial.SerialBlob;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.sql.Blob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Objects;
/**
* This is a class for persisting <code>X509Certificate</code> objects via
* Hibernate. This class provides the mapping from <code>X509Certificate</code>
* to Hibernate commands to JDBC.
*/
@NoArgsConstructor(access= AccessLevel.PUBLIC)
public final class X509CertificateType implements UserType {
@Override
public int getSqlType() {
return Types.BLOB;
}
/**
* Returns the <code>X509Certificate</code> class.
*
* @return <code>X509Certificate</code> class
*/
@Override
public Class returnedClass() {
return X509Certificate.class;
}
/**
* Compares x and y using {@link Objects#equals(Object, Object)}.
*
* @param x x
* @param y y
* @return value from equals call
*/
@Override
public boolean equals(final Object x, final Object y) {
return Objects.equals(x, y);
}
/**
* Returns the hash code of x, which will be the same as from
* <code>X509Certificate</code>.
*
* @param x x
* @return hash value of x
*/
@Override
public int hashCode(final Object x) {
assert x != null;
return x.hashCode();
}
/**
* Converts the X509Certificate that is stored as a <code>String</code> and
* converts it to an <code>X509Certificate</code>.
*
* @param rs
* result set
* @param names
* column names
* @param session
* session
* @param owner
* owner
* @return X509Certificate of String
* @throws HibernateException
* if unable to convert the String to an X509Certificate
* @throws SQLException
* if unable to retrieve the String from the result set
*/
@Override
public Object nullSafeGet(final ResultSet rs, final int names,
final SharedSessionContractImplementor session, final Object owner)
throws HibernateException, SQLException {
final Blob cert = rs.getBlob(names);
if (cert == null) {
return null;
}
try {
InputStream inputStream = new ByteArrayInputStream(
cert.getBytes(1, (int) cert.length()));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return cf.generateCertificate(inputStream);
} catch (CertificateException e) {
final String msg = String.format(
"unable to convert certificate: %s", cert);
throw new HibernateException(msg, e);
}
}
/**
* Converts the <code>X509Certificate</code> <code>value</code> to a
* <code>String</code> and stores it in the database.
*
* @param st prepared statement
* @param value X509Certificate
* @param index index
* @param session session
* @throws SQLException if unable to set the value in the result set
*/
@Override
public void nullSafeSet(final PreparedStatement st, final Object value,
final int index, final SharedSessionContractImplementor session)
throws SQLException {
if (value == null) {
st.setString(index, null);
} else {
try {
Blob blob =
new SerialBlob(((Certificate) value).getEncoded());
st.setBlob(index, blob);
} catch (Exception e) {
final String msg =
String.format("unable to convert certificate: %s",
value.toString());
throw new HibernateException(msg, e);
}
}
}
/**
* Returns <code>value</code> since <code>X509Certificate</code> is
* immutable.
*
* @param value value
* @return value
* @throws HibernateException will never be thrown
*/
@Override
public Object deepCopy(final Object value) throws HibernateException {
return value;
}
/**
* Returns false because <code>X509Certificate</code> is immutable.
*
* @return false
*/
@Override
public boolean isMutable() {
return false;
}
/**
* Returns <code>value</code> because <code>X509Certificate</code> is
* immutable.
*
* @param value value
* @return value
*/
@Override
public Serializable disassemble(final Object value) {
return (Serializable) value;
}
/**
* Returns <code>cached</code> because <code>X509Certificate</code> is
* immutable.
*
* @param cached cached
* @param owner owner
* @return cached
*/
@Override
public Object assemble(final Serializable cached, final Object owner) {
return cached;
}
/**
* Returns the <code>original</code> because <code>X509Certificate</code> is
* immutable.
*
* @param original original
* @param target target
* @param owner owner
* @return original
*/
@Override
public Object replace(final Object original, final Object target,
final Object owner) {
return original;
}
}

View File

@ -0,0 +1,477 @@
{
"TCG": {
"Processors": {
"ID": "0x00010000",
"Types": {
"0x00000002": "CPU",
"0x00000003": "Math Processor",
"0x00000004": "DSP Processor",
"0x00000005": "Video Processor",
"0x00000006": "GPU"
}
},
"Containers": {
"ID": "0x00020000",
"Types": {
"0x00000002": "Desktop",
"0x00000003": "Low Profile Desktop",
"0x00000004": "Pizza Box",
"0x00000005": "Mini Tower",
"0x00000006": "Tower",
"0x00000007": "Portable",
"0x00000008": "Laptop",
"0x00000009": "Notebook",
"0x0000000A": "Hand Held",
"0x0000000B": "Docking Station",
"0x0000000C": "All in One",
"0x0000000D": "Sub Notebook",
"0x0000000E": "Space-saving",
"0x0000000F": "Lunch Box",
"0x00000010": "Main Server Chassis",
"0x00000011": "Expansion Chassis",
"0x00000012": "Sub Chassis",
"0x00000013": "Bus Expansion Chassis",
"0x00000014": "Peripheral Chassis",
"0x00000015": "RAID Chassis",
"0x00000016": "Rack Mount Chassis",
"0x00000017": "Sealed-case PC",
"0x00000018": "Multi-system Chassis",
"0x00000019": "Compact PCI",
"0x0000001A": "Advanced TCA",
"0x0000001B": "Blade",
"0x0000001C": "Blade Enclosure",
"0x0000001D": "Tablet",
"0x0000001E": "Convertible",
"0x0000001F": "Detachable",
"0x00000020": "IoT Gateway",
"0x00000021": "Embedded PC",
"0x00000022": "MiniPC",
"0x00000023": "Stick PC",
"0x00000024": "1U Rack Mount Chassis",
"0x00000025": "2U Rack Mount Chassis",
"0x00000026": "3U Rack Mount Chassis",
"0x00000027": "4U Rack Mount Chassis",
"0x00000028": "5U Rack Mount Chassis",
"0x00000029": "6U Rack Mount Chassis",
"0x0000002A": "7U Rack Mount Chassis",
"0x0000002B": "8U Rack Mount Chassis"
}
},
"IC Boards": {
"ID": "0x00030000",
"Types": {
"0x00000002": "Daughter Board",
"0x00000003": "Motherboard",
"0x00000004": "Riser Card"
}
},
"Modules": {
"ID": "0x00040000",
"Types": {
"0x00000002": "SAS Bridgeboard",
"0x00000003": "Processor Module",
"0x00000004": "I/O Module",
"0x00000005": "Memory Module",
"0x00000006": "Power Module",
"0x00000007": "Processor/Memory Module",
"0x00000008": "Processor/IO Module",
"0x00000009": "TPM"
}
},
"Controllers": {
"ID": "0x00050000",
"Types": {
"0x00000002": "Video Controller",
"0x00000003": "SCSI Controller",
"0x00000004": "Ethernet Controller",
"0x00000005": "Token Ring Controller",
"0x00000006": "Audio/Sound Controller",
"0x00000007": "PATA Controller",
"0x00000008": "SATA Controller",
"0x00000009": "SAS Controller",
"0x0000000A": "LED Display Controller",
"0x0000000B": "RAID Controller",
"0x0000000C": "Remote Access Controller",
"0x0000000E": "USB Controller",
"0x0000000F": "Multi-function Storage Controller",
"0x00000010": "Multi-function Network Controller",
"0x00000011": "Smart IO Controller"
}
},
"Memory": {
"ID": "0x00060000",
"Types": {
"0x00000002": "Port Controller",
"0x00000003": "Baseboard Management Controller",
"0x00000004": "DRAM Memory",
"0x00000005": "EDRAM Memory",
"0x00000006": "VRAM Memory",
"0x00000007": "SRAM Memory",
"0x00000008": "RAM Memory",
"0x00000009": "ROM Memory",
"0x0000000A": "FLASH Memory",
"0x0000000B": "EEPROM Memory",
"0x0000000C": "FEPROM Memory",
"0x0000000D": "EPROM Memory",
"0x0000000E": "CDRAM Memory",
"0x0000000F": "3DRAM Memory",
"0x00000010": "SDRAM Memory",
"0x00000011": "SGRAM Memory",
"0x00000012": "RDRAM Memory",
"0x00000013": "DDR Memory",
"0x00000014": "DDR2 Memory",
"0x00000015": "DDR3 Memory",
"0x00000016": "DDR4 Memory",
"0x00000017": "LPDDR Memory",
"0x00000018": "LPDDR2 Memory",
"0x00000019": "LPDDR3 Memory",
"0x0000001A": "LPDDR4 Memory",
"0x0000001B": "NVRAM Memory",
"0x0000001C": "3D Xpoint Memory"
}
},
"Storage": {
"ID": "0x00070000",
"Types": {
"0x00000002": "Storage Drive",
"0x00000003": "SSD Drive",
"0x00000004": "M.2 Drive",
"0x00000005": "HDD Drive"
}
},
"Media Drives": {
"ID": "0x00080000",
"Types": {
"0x00000002": "Floppy Drive",
"0x00000003": "Tape Drive",
"0x00000004": "PCIe Drive",
"0x00000005": "CD Drive",
"0x00000006": "DVD Drive",
"0x00000007": "Blu-Ray Drive"
}
},
"Network Adapters": {
"ID": "0x00090000",
"Types": {
"0x00000002": "Ethernet Adapter",
"0x00000003": "WiFi Adapter",
"0x00000004": "Bluetooh Adapter",
"0x00000005": "Cellular Adapter",
"0x00000006": "Zigbee Adapter",
"0x00000007": "3G Cellular Adapter",
"0x00000008": "4G Cellular Adapter",
"0x00000009": "5G Cellular Adapter",
"0x0000000A": "Network Switch",
"0x0000000B": "Network Router"
}
},
"Energy Object": {
"ID": "0x000A0000",
"Types": {
"0x00000002": "Power Supply",
"0x00000003": "Battery",
"0x00000004": "Coin Battery",
"0x00000005": "Capacitor Battery"
}
},
"Sensors": {
"ID": "0x000B0000",
"Types": {
"0x00000002": "Optical Sensor",
"0x00000003": "Temperature Sensor",
"0x00000004": "Proximity Sensor",
"0x00000005": "IR Sensor",
"0x00000006": "Chemical Sensor",
"0x00000007": "Motion Detection Sensor",
"0x00000008": "Level Sensor",
"0x00000009": "Gyroscopic Sensor",
"0x0000000A": "Humidity Sensor",
"0x0000000B": "Accelerometer Sensor"
}
},
"Display Devices": {
"ID": "0x000C0000",
"Types": {
"0x00000002": "LCD Display Panel",
"0x00000003": "LED Display Panel",
"0x00000004": "OLED Display Panel",
"0x00000005": "CRT Display Panel"
}
},
"Cooling": {
"ID": "0x000D0000",
"Types": {
"0x00000002": "Thermal Assembly",
"0x00000003": "Fan",
"0x00000004": "Chassis Fan",
"0x00000005": "Socket Fan",
"0x00000006": "Heatsink",
"0x00000007": "Liquid Cooling"
}
},
"Input Devices": {
"ID": "0x000E0000",
"Types": {
"0x00000002": "Mouse",
"0x00000003": "Track Ball",
"0x00000004": "Track Point",
"0x00000005": "Glide Point",
"0x00000006": "Touch Pad",
"0x00000007": "Touch Screen",
"0x00000008": "Camera",
"0x00000009": "Fingerprint Reader",
"0x0000000A": "Keyboard",
"0x0000000B": "Smartcard Reader",
"0x0000000C": "Biometric Reader",
"0x0000000D": "Joystick",
"0x0000000E": "Gaming Controller",
"0x0000000F": "IR Camera",
"0x00000010": "Facial Recognition Camera",
"0x00000011": "Scanner"
}
},
"Slots": {
"ID": "0x000F0000",
"Types": {
"0x00000002": "Socket",
"0x00000003": "ISA Slot",
"0x00000004": "PCI Slot",
"0x00000005": "AGP Slot",
"0x00000006": "PCI-X Slot",
"0x00000007": "M.2 Slot",
"0x00000008": "MXM Slot",
"0x00000009": "PCI Express Slot",
"0x0000000A": "PCI Express Mini",
"0x0000000B": "PC-98 Slot",
"0x0000000C": "Memory Slot"
}
},
"Ports": {
"ID": "0x00100000",
"Types": {
"0x00000002": "Parallel Port",
"0x00000003": "Serial Port",
"0x00000004": "SCSI Port",
"0x00000005": "MIDI Port",
"0x00000006": "USB Port",
"0x00000007": "Firewire Port",
"0x00000008": "PCMCIA Port",
"0x00000009": "ATA Port",
"0x0000000A": "SATA Port",
"0x0000000B": "SAS Port",
"0x0000000C": "Optical Port",
"0x0000000D": "DisplayPort",
"0x0000000E": "Mini DisplayPort",
"0x0000000F": "HDMI Port",
"0x00000010": "Mini HDMI Port",
"0x00000011": "Micro HDMI Port",
"0x00000012": "Thunderbolt Port",
"0x00000013": "VGA Port",
"0x00000014": "Mini VGA Port",
"0x00000015": "DVI Port",
"0x00000016": "DVI-I Port",
"0x00000017": "DVI-D Port",
"0x00000018": "DVI-A Port",
"0x00000019": "Mini DVI Port",
"0x0000001A": "Micro DVI Port",
"0x0000001B": "Ethernet Port",
"0x0000001C": "ADB Port",
"0x0000001D": "Mac Serial Port",
"0x0000001E": "PS/2 Port",
"0x0000001F": "Surround Sound Port",
"0x00000020": "Stereo Port",
"0x00000021": "Dolby 5.1 Port",
"0x00000022": "Dolby 7.1 Port",
"0x00000023": "Dolby 7.2 Port",
"0x00000024": "Line In Port",
"0x00000025": "Microphone Port",
"0x00000026": "Speaker Port",
"0x00000027": "Digital Audio Port",
"0x00000028": "TOSLINK Port"
}
},
"Discrete Component": {
"ID": "0x00110000",
"Types": {
"0x00000002": "Capacitor",
"0x00000003": "Resistor",
"0x00000004": "Inductor",
"0x00000005": "Diode",
"0x00000006": "Crystal Oscilator",
"0x00000007": "Logic Gate",
"0x00000008": "Ferrite Beads",
"0x00000009": "Transistor",
"0x0000000A": "Fuse",
"0x0000000B": "Voltage Regulator",
"0x0000000C": "DC/DC Converter",
"0x0000000D": "Switching Regulator",
"0x0000000E": "Power Switch"
}
},
"Cabling": {
"ID": "0x00120000",
"Types": {
"0x00000002": "AC Adapter",
"0x00000003": "Power Cord",
"0x00000004": "Serial ATA Cable",
"0x00000005": "Serial ATA Power Cable",
"0x00000006": "Drive Cable",
"0x00000007": "Power Supply Cable",
"0x00000008": "IDE Cable",
"0x00000009": "Molex Cable",
"0x0000000A": "Ribbon Cable",
"0x0000000B": "PCI Express Cable"
}
},
"Firmware": {
"ID": "0x00130000",
"Types": {
"0x00000002": "UEFI",
"0x00000003": "System BIOS",
"0x00000004": "Drive BIOS",
"0x00000005": "Bootloader",
"0x00000006": "System Management Module"
}
}
},
"SMBIOS": {
"BIOS": {
"ID": "0x00000000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown"
}
},
"System": {
"ID": "0x00010000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown"
}
},
"Baseboard": {
"ID": "0x00020000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown",
"0x00000003": "Server Blade",
"0x00000004": "Connectivity Switch",
"0x00000005": "System Management Module",
"0x00000006": "Processor Module",
"0x00000007": "I/O Module",
"0x00000008": "Memory Module",
"0x00000009": "Daughter board",
"0x0000000A": "Motherboard (includes processor, memory, and I/O)",
"0x0000000B": "Processor/Memory Module",
"0x0000000C": "Processor/IO Module",
"0x0000000D": "Interconnect board"
}
},
"Chassis": {
"ID": "0x00030000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown",
"0x00000003": "Desktop",
"0x00000004": "Low Profile Desktop",
"0x00000005": "Pizza Box",
"0x00000006": "Mini Tower",
"0x00000007": "Tower",
"0x00000008": "Portable",
"0x00000009": "Laptop",
"0x0000000A": "Notebook",
"0x0000000B": "Hand Held",
"0x0000000C": "Docking Station",
"0x0000000D": "All in One",
"0x0000000E": "Sub Notebook",
"0x0000000F": "Space-saving",
"0x00000010": "Lunch Box",
"0x00000011": "Main Server Chassis",
"0x00000012": "Expansion Chassis",
"0x00000013": "SubChassis",
"0x00000014": "Bus Expansion Chassis",
"0x00000015": "Peripheral Chassis",
"0x00000016": "RAID Chassis",
"0x00000017": "Rack Mount Chassis",
"0x00000018": "Sealed-case PC",
"0x00000019": "Multi-system chassis",
"0x0000001A": "Compact PCI",
"0x0000001B": "Advanced TCA",
"0x0000001C": "Blade",
"0x0000001D": "Blade Enclosure",
"0x0000001E": "Tablet",
"0x0000001F": "Convertible",
"0x00000020": "Detachable",
"0x00000021": "IoT Gateway",
"0x00000022": "Embedded PC",
"0x00000023": "Mini PC",
"0x00000024": "Stick PC"
}
},
"Processor": {
"ID": "0x00040000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown",
"0x00000003": "Central Processor",
"0x00000004": "Math Processor",
"0x00000005": "DSP Processor",
"0x00000006": "Video Processor"
}
},
"RAM": {
"ID": "0x00110000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown",
"0x00000003": "DRAM",
"0x00000004": "EDRAM",
"0x00000005": "VRAM",
"0x00000006": "SRAM",
"0x00000007": "RAM",
"0x00000008": "ROM",
"0x00000009": "FLASH",
"0x0000000A": "EEPROM",
"0x0000000B": "FEPROM",
"0x0000000C": "EPROM",
"0x0000000D": "CDRAM",
"0x0000000E": "3DRAM",
"0x0000000F": "SDRAM",
"0x00000010": "SGRAM",
"0x00000011": "RDRAM",
"0x00000012": "DDR",
"0x00000013": "DDR2",
"0x00000014": "DDR2 FB-DIMM",
"0x00000015": "Reserved",
"0x00000016": "Reserved",
"0x00000017": "Reserved",
"0x00000018": "DDR3",
"0x00000019": "FBD2",
"0x0000001A": "DDR4",
"0x0000001B": "LPDDR",
"0x0000001C": "LPDDR2",
"0x0000001D": "LPDDR3",
"0x0000001E": "LPDDR4",
"0x0000001F": "Logical non-volatile device",
"0x00000020": "HBM (High Bandwidth Memory)",
"0x00000021": "HBM2 (High Bandwidth Memory Generation 2)",
"0x00000022": "DDR5",
"0x00000023": "LPDDR5"
}
},
"Power Supply": {
"ID": "0x00270000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown"
}
},
"TPM": {
"ID": "0x002B0000",
"Types": {
"0x00000001": "Other",
"0x00000002": "Unknown"
}
}
}
}

View File

@ -0,0 +1,233 @@
{
"VendorTable": {
"_comment_1": "UUIDS listed in the UEFI Specification",
"eb9d2d30-2d88-11d3-9a16-0090273fc14d": "ACPI_TABLE_GUID",
"eb9d2d32-2d88-11d3-9a16-0090273fc14d": "SAL_SYSTEM_TABLE_GUID",
"eb9d2d31-2d88-11d3-9a16-0090273fc14d": "SMBIOS_TABLE_GUID",
"f2fd1544-9794-4a2c-992e-e5bbcf20e394": "SMBIOS3_TABLE_GUID",
"eb9d2d2f-2d88-11d3-9a16-0090273fc14d": "MPS_TABLE_GUID",
"8868e871-e4f1-11d3-bc22-0080c73c8881": "EFI_ACPI_TABLE_GUID",
"87367f87-1119-41ce-aaec-8be01101f558": "EFI_JSON_CONFIG_DATA_TABLE_GUID",
"35e7a725-8dd2-4cac-8011-33cda8109056": "EFI_JSON_CAPSULE_DATA_TABLE_GUID",
"dbc461c3-b3de-422a-b9b4-9886fd49a1e5": "EFI_JSON_CAPSULE_RESULT_TABLE_GUID",
"77ab535a-45fc-624b-5560-f7b281d1f96e": "EFI_VIRTUAL_DISK_GUID",
"3d5abd30-4175-87Ce-6d64-d2ADe523C4bb": "EFI_VIRTUAL_CD_GUID",
"5Cea02c9-4d07-69d3-269f-4496Fbe096f9": "EFI_PERSISTENT_VIRTUAL_DISK_GUID",
"08018188-42cd-bb48-100f-5387D53ded3d": "EFI_PERSISTENT_VIRTUAL_CD_GUID",
"_comment_2": "DXE GUIds from https://github.com/linuxboot/linuxboot/blob/master/boards/qemu/image-files.txt",
"fc510ee7-ffdc-11d4-bd41-0080c73c8881": "DXE Apriori-FVRECOVERY",
"1b45cc0a-156a-428a-62af-49864da0e6e6": "PEI Apriori file name",
"80cf7257-87ab-47f9-a3fe-d50b76d89541": "PcdDxe",
"b601f8c4-43b7-4784-95b1-f4226cb40cee": "RuntimeDxe",
"f80697e9-7fd6-4665-8646-88e33ef71dfc": "SecurityStubDxe",
"1a1e4886-9517-440e-9fde-3be44cee2136": "CpuDxe",
"11a6edf6-a9be-426d-a6cc-b22fe51d9224": "PciHotPlugInitDxe",
"128fb770-5e79-4176-9e51-9bb268a17dd1": "PciHostBridgeDxe",
"93b80004-9fb3-11d4-9a3a-0090273fc14d": "PCI Bus Driver - PciBusDxe",
"9b680fce-ad6b-4f3a-b60b-f59899003443": "DevicePathDxe",
"f9d88642-0737-49bc-81b5-6889cd57d9ea": "SmbiosDxe",
"4110465d-5ff3-4f4b-b580-24ed0d06747a": "SmbiosPlatformDxe",
"9622e42c-8e38-4a08-9e8f-54f784652f6b": "AcpiTableDxe",
"49970331-e3fa-4637-9abc-3b7868676970": "AcpiPlatform",
"7e374e25-8e01-4fee-87f2-390c23c606cd": "ACPI data",
"bdce85bb-fbaa-4f4e-9264-501a2c249581": "S3SaveStateDxe",
"d9dcc5df-4007-435e-9098-8970935504b2": "PlatformDxe",
"8657015b-ea43-440d-949a-af3be365c0fc": "IoMmuDxe",
"cbd2e4d5-7068-4ff5-b462-9822b4ad8d60": "VariableRuntimeDxe",
"_comment_3": "PIWG Dxe driver Files (FvFile)from https://bugs.launchpad.net/ubuntu/+source/edk2/+bug/1272444",
"70d57d67-7f05-494d-a014-b75d7345b700": "Storage Security Command Driver",
"3acc966d-8e33-45c6-b4fe-62724bcd15a9": "AHCI Bus Driver",
"67bbc344-84bc-4e5c-b4df-f5e4a00e1f3a": "Host Controller Driver",
"86edaae5-073c-4c89-b949-8984ac8a55f3": "MMC/SD Media Device Driver",
"9e863906-a40f-4875-977F-5b93ff237fc6": "Serial Terminal Driver",
"a6cc6bc8-2ada-46C3-bba4-e99672CC9530": "PCI Serial Driver",
"69fd8e47-a161-4550-b01a-5594ceb2b2b2": "PCI IDE/ATAPI Bus Driver",
"51ccf399-4fdf-4e55-a45b-e123f84d456a": "Platform Console Management Driver",
"6b38f7b4-ad98-40e9-9093-aca2b5a253c4": "Generic Disk I/O Driver",
"2d2e62cf-9ecf-43b7-8219-94e7fC713dfe": "Usb Keyboard Driver",
"9fb4b4a7-42C0-4bcd-8540-9bcc6711f83e": "Usb Mass Storage Driver",
"e3752948-b9a1-4770-90c4-df41c38986be": "QEMU Video Driver",
"240612B7-a063-11d4-9a3a-0090273fc14d": "Usb Bus Driver",
"bdfe430e-8F2a-4db0-9991-6f856594777e": "Usb Ehci Driver",
"2fb92efa-2ee0-4bae-9eB6-7464125E1EF7": "Usb Ehci Driver",
"a92cdb4b-82f1-4e0b-a516-8a655d371524": "Virtio Network Driver",
"4579b72d-7ec4-4dd4-8486-083c86b182a7": "iSCSI Driver",
"3b1deaB5-c75d-442e-9238-8e2ffb62b0bb": "UEFI PXE Base Code Driver",
"6b6963ab-906d-4a65-a7ca-bd40e5d6af2b": "UDP Network Service Driver",
"6d6963ab-906d-4a65-a7ca-bd40e5d6af4d": "Tcp Network Service Driver",
"dc3641b8-2fa8-4ed3-bc1f-f9962a03454b": "MTFTP4 Network Service Driver",
"9fb1a1f3-3b71-4324-b39a-745cbb015fff": "IP4 Network Service Driver",
"26841bde-920a-4e7a-9Fbe-637f477143a6": "IP4 CONFIG Network Service Driver",
"94734718-0bbc-47fb-96a5-ee7a5ae6a2ad": "DHCP Protocol Driver",
"529d3f93-e8e9-4e73-b1e1-bdf6a9d50113": "ARP Network Service Driver",
"e4f61863-fe2c-4b56-a8d4-08519bc439df": "VLAN Configuration Driver",
"a2f436ea-a127-4ef8-957c-8048606ff670": "Simple Network Protocol Driver",
"961578fe-b6b7-44c3-af35-6bc705cd2b1f": "FAT File System Driver",
"0abd8284-6da3-4616-971a-83a5148067ba": "ISA Floppy Driver",
"3dc82376-637b-40a6-a8fc-a565417f2c38": "PS/2 Keyboard Driver",
"93b80003-9fb3-11d4-9a3a-0090273fc14d": "ISA Serial Driver",
"240612b5-a063-11d4-9a3a-0090273fc14a": "ISA Bus Driver",
"99549f44-49bb-4820-b9d2-901329412d67": "IDE Controller Init Driver",
"0a66e322-3740-4cce-ad62-bd172cecca35": "Scsi Disk Driver",
"1fa1f39e-feff-4aae-bd7b-38a070a3b609": "Partition Driver",
"9e863906-a40f-4875-977f-5b93ff237fc6": "Serial Terminal Driver",
"cccb0c28-4b24-11d5-9a5a-0090273fc14d": "Graphics Console Driver",
"408edcec-cf6d-477c-a5a8-b4844e3de281": "Console Splitter Driver",
"fab5d4f4-83c0-4aaf-8480-442d11df6cea": "Virtio SCSI Host Driver",
"11d92dfb-3Ca9-4f93-ba2e-4780ed3e03b5": "Virtio Block Driver",
"33cb97af-6c33-4c42-986b-07581fa366d4": "Block MMIO to Block IO Driver",
"_comment_4": "PIWG Volumes (Fv)",
"a881d567-6cb0-4eee-8435-2e72d33e45B5": "PIWG Default Volume",
"_comment_5": "UEFI UUIDS for Certificates",
"3c5766e8-269c-4e34-aa14-ed776e85b3b6": "EFI_CERT_RSA2048_GUID",
"e2b36190-879b-4a3d-ad8d-f2e7bba32784": "EFI_CERT_RSA2048_SHA256_GUID",
"c1c41626-504c-4092-aca9-41f936934328": "EFI_CERT_SHA256_GUID",
"826ca512-cf10-4ac9-b187-be01496631bd": "EFI_CERT_SHA1_GUID",
"67f8444f-8743-48f1-a328-1eaab8736080": "EFI_CERT_RSA2048_SHA1_GUID",
"a5c059a1-94e4-4aa7-87b5-ab155c2bf072": "EFI_CERT_X509_GUID",
"0b6e5233-a65c-44c9-9407-d9ab83bfc8bd": "EFI_CERT_SHA224_GUID",
"ff3e5307-9fd0-48c9-85f1-8ad56c701e01": "EFI_CERT_SHA384_GUID",
"093e0fae-a6c4-4f50-9f1b-d41e2b89c19a": "EFI_CERT_SHA512_GUID",
"3bd2a492-96c0-4079-b420-fcf98ef103ed": "EFI_CERT_X509_SHA256_GUID",
"7076876e-80c2-4ee6-aad2-28b349a6865b": "EFI_CERT_X509_SHA384_GUID",
"446dbf63-2502-4cda-bcfa-2465d2b0fe9d": "EFI_CERT_X509_SHA512_GUID",
"a7717414-c616-4977-9420-844712a735bf": "EFI_CERT_TYPE_RSA2048_SHA256_GUID",
"_comment_6": "UEFI defined variables",
"452e8ced-dfff-4b8c-ae01-5118862e682c": "EFI_CERT_EXTERNAL_MANAGEMENT_GUID",
"d719b2cb-3d3a-4596-a3bc-dad00e67656f": "EFI_IMAGE_SECURITY_DATABASE_GUID",
"4aafd29d-68df-49ee-8aa9-347d375665a7": "EFI_CERT_TYPE_PKCS7_GUID",
"c12a7328-f81f-11d2-ba4b-00a0c93ec93b": "EFI System Partition",
"024DEE41-33E7-11D3-9D69-0008C781F39F": "Partition containing a legacy MBR",
"_comment_7": "RHBoot UEFI Application UUIDs From listed in RHBoot (RHShim) https://github.com/rhboot/efivar/blob/master/src/guids.txt",
"0abba7dc-e516-4167-bbf5-4d9d1c739416": "fwupdate:",
"3b8c8162-188c-46a4-aec9-be43f1d65697": "ux_capsule",
"605dab50-e046-4300-abb6-3dd810dd8b23": "RH_Shim",
"8be4df61-93ca-11d2-aa0d-00e098032b8c": "EFI_Global_Variable",
"91376aff-cba6-42be-949d-06fde81128e8": "GRUB",
"_comment_8": "Partition Table GUIDs",
"0fc63daf-8483-4772-8e79-3d69d8477de4": "Linux filesystem data",
"e6d6d379-f507-44c2-a23c-238f2a3df928": "Logical Volume Manager (LVM) partition",
"4f68bce3-e8cd-4db1-96e7-fbcaf984b709": "Root partition (x86-64)",
"a19d880f-05fc-4d3b-a006-743f0f84911e": "RAID partition",
"933ac7e1-2eb4-4f13-b844-0e14e2aef915": "/home partition[ (x86-64)",
"ebd0a0a2-b9e5-4433-87c0-68b6b72699c7": "GPT Basic data partition",
"_comment_9": "RHBoot Lenovo specific UUIDS",
"3cc24e96-22c7-41d8-8863-8e39dcdcc2cf": "lenovo",
"82988420-7467-4490-9059-feb448dd1963": "lenovo_me_config",
"f7e615b-0d45-4f80-88dc-26b234958560": "lenovo_diag",
"665d3f60-ad3e-4cad-8e26-db46eee9f1b5": "lenovo_rescue",
"721c8b66-426c-4e86-8e99-3457c46ab0b9": "lenovo_setup",
"f46ee6f4-4785-43a3-923d-7f786c3c8479": "lenovo_startup_interrupt",
"126a762d-5758-4fca-8531-201a7f57f850": "lenovo_boot_menu",
"a7d8d9a6-6ab0-4aeb-ad9d-163e59a7a380": "lenovo_diag_splash",
"_comment_10": "Company UUIDs (From Internet searches)",
"77fa9abd-0359-4d32-bd60-28f4e78f784b": "Microsoft Inc.",
"f5a96b31-dba0-4faa-a42a-7a0c9832768e": "HPE Inc.",
"2879c886-57ee-45cc-b126-f92f24f906b9": "SUSE Certificate",
"70564dce-9afc-4ee3-85fc-949649d7e45c": "Dell Inc.",
"_comment_11": "Intel GUIDS",
"bfcc0833-2125-42d1-8c6d-13821e23c078": "Intel(R) Desktop Boards",
"80b3ad5b-9880-4af9-a645-e56a68be89de": "Intel(R) CISD FW Update",
"_comment_12": "Microsoft GUIDS",
"e3c9e316-0b5c-4db8-817d-f92df00215ae": "Microsoft Reserved Partition (MSR)",
"5808c8aa-7e8f-42e0-85d2-e1e90434cfb3": "Logical Disk Manager (LDM) metadata partition ",
"af9b60a0-1431-4f62-bc68-3311714a69ad": "Logical Disk Manager data partition",
"de94bba4-06d1-4d40-a16a-bfd50179d6ac": "Windows Recovery Environment",
"9f25ee7a-e7b7-11db-94b5-f7e662935912": "Windows Boot Loader",
"_comment_13": "Linux specific GUIDS",
"0fc63daf-8483-4772-8e79-3d69d8477de": "Linux filesystem data",
"44479540-f297-41b2-9af7-d131d5f0458a4": "Root partition (x86)",
"69dad710-2ce4-4e3c-b16c-21a1d49abed3": "Root partition (32-bit ARM)",
"b921b045-1df0-41c3-af44-4c6f280d3fae": "Root partition (64-bit ARM/AArch64)",
"0657fd6d-a4ab-43c4-84e5-0933c84b4f4f": "Swap partition",
"3b8f8425-20e0-4f3b-907f-1a25a76f98e8": "/srv (server data) partition",
"7ffec5c9-2d00-49b7-8941-3ea10a5586b7": "Plain dm-crypt partitiont",
"ca7d7ccb-63ed-4c53-861c-1742536059cc": "LUKS partition",
"_comment_14": "Linux Boot GUIDS https://github.com/linuxboot/linuxboot/blob/master/boards/s2600wf/vendor-files.txt",
"9cfd802c-09a1-43d6-8217-aa49c1f90d2c": "Intel Management Engine BIOS Extension (Mebx)",
"b62efbbb-3923-4cb9-a6e8-db818e828a80": "Intel Management Engine BIOS Extension (Mebx) Setup Browser",
"9ce4325e-003e-11e3-b582-b8ac6f199a57": "Non-Volatile Dual In-line Memory Module (NVDIMM) Driver",
"ea9de6d5-7839-46f7-9e63-4de8b00e2e5d": "NVM DIMM Human Interface Infrastructure (HII)",
"56a1b86f-0d4a-485d-87de-ad0eba1c8c2a": "IBM C Video Gop",
"a1f436ea-a127-4ef8-957c-8048606ff670": "SnpDxe",
"a210f973-229d-4f4d-aa37-9895e6c9eaba": "DpcDxe",
"025bbfc7-e6a9-4b8b-82ad-6815a1aeaf4a": "MNP Network Service Driver - MnpDxe",
"b44b2005-42bc-41c9-80af-abd7dc7d6923": "RSTesSATAEFI",
"15e1e31a-9f9d-4c84-82fb-1a707fc0f63b": "RSTeSATAEFI",
"2cc25173-bd9f-4c89-89cc-29256a3fd9c3": "RSTesSATALegacy",
"bd5d4ca5-674f-4584-8cf9-ce4ea1f54dd1": "RSTeSATALegacy",
"_comment_15": "WinNt GUIDs, add if they are still found in use https://sourceforge.net/p/uefinotes/wiki/FV%20Sources/?version=3",
"fc5c7020-1a48-4198-9be2-ead5abc8cf2f": "BdsDxe",
"d0893f05-b06d-4161-b947-9be9b85ac3a1": "SnpNt32Dxe",
"9b3ada4f-ae56-4c24-8Dea-f03b7558ae50": "PcdPeim",
"34c8c28F-b61c-45a2-8f2e-89e46becc63b": "PeiVariable",
"fe5cea76-4f72-49e8-986f-2cd899dffe5d": "FaultTolerantWriteDxe",
"_comment_16": "Linux Boot Image files UEFI Platform Initialization (PI) specifications Driver Execution Environment (DXE) Architectural protocols and platform modules https://github.com/linuxboot/linuxboot/blob/master/boards/winterfell/image-files.txt",
"5ae3f37e-4eae-41ae-8240-35465b5e81eb": "CORE_DXE",
"cbc59c4a-383a-41eb-a8ee-4498aea567e4": "DXE Runtime",
"3c1de39f-d207-408a-aacc-731cfb7f1dd7": "DXE PciBus",
"80e66e0a-ccd1-43fa-a7b1-2d5ee0f13910": "DXE PciRootBridge",
"9f3a0016-ae55-4288-829d-d22fd344c347": "DXE AmiBoardInfo",
"13ac6dd0-73d0-11d4-b06b-00aa00bd6de7": "DXE EBC",
"e03abadf-e536-4e88-b3a0-b77f78eb34fe": "CPU DXE",
"b7d19491-e55a-470d-8508-85a5dfa41974": "SBDXE",
"e23f86e1-056e-4888-b685-cfcd67c179d4": "DXE SBRun",
"e4ecd0b2-e277-4f2b-becb-e4d75c9a812e": "NBDXE",
"5ad34ba6-f024-2149-52e4-da0398e2bb9": "DXE Services Table",
"_comment_17": "ACPI configuration and tables",
"750890a6-7acf-4f4f-81bd-b400c2bea95a": "AcpiModeEnable",
"d4c05cd1-5eae-431d-a095-13a9e5822045": "MPST",
"db93cb2c-bf1c-431a-abc8-8737bc2afc1f": "PRAD-ACPI-table",
"3bc5b795-a4e0-4d56-9321-316d18a7aefe": "PRAD",
"16d0a23e-c09c-407d-a14a-ad058fdd0ca1": "ACPI",
"26a2481e-4424-46a2-9943-cc4039ead8f8": "S3Save",
"efd652cc-0e99-40f0-96c0-e08c089070fc": "S3Restore",
"8c783970-f02a-4a4d-af09-8797a51eec8d": "PowerManagement",
"299141bb-211a-48a5-92c0-6f9a0a3a006e0": "PowerManagement-ACPI-table",
"2df10014-cf21-4280-8c3f-e539b8ee5150": "PpmPolicyInitDxe",
"4b680e2d-0d63-4f62-b930-7ae995b9b3a3": "SmBusDxe",
"_comment_18": "SMM handlers",
"4a37320b-3fb3-4365-9730-9e89c600395d": "SmmDispatcher",
"753630c9-fae5-47a9-bbbf-88d621cd7282": "SmmChildDispatcher",
"be216ba8-38c4-4535-a6ca-5dca5b43addf": "SmiVariable",
"a56897a1-a77f-4600-84db-22b0a801fa9a": "SmmRuntime",
"d2596f82-f0e1-49fa-95bc-62012c795728": "SmmBase Data",
"69009842-63f2-43db-964b-efad1c39ec85": "SmmBase Data",
"d0632c90-afd7-4492-b186-257c63143c61": "SmmBase",
"7e2d983f-f703-4a29-9761-77b51f5354ed": "SmmCommunicate",
"_comment_19": "CMOS and NVRAM handlers",
"6869c5b3-ac8d-4973-8b37-e354dbf34add": "CmosManagerSmm",
"842a454a-75e5-408b-8b1c-36420e4e3f21": "NvramSmi",
"5446c293-339b-47cd-b719-585de39408cc": "PostReport",
"71ca9ca1-325d-4bfe-afa3-2ec5c94a8680": "DmAcpi",
"cef68c66-06ab-4fb3-a3ed-5ffa885b5725": "SMBiosBoard",
"b13edd38-684c-41ed-a305-d7b7e32497df": "SMBios64",
"ded7956d-7e20-4f20-91a1-190439b04d5b": "SmbiosGetFlashData64",
"daf4bf89-ce71-4917-b522-c89d32fbc59f": "SmbiosStaticData",
"_comment_20": "Apple GUIDS",
"48465300-0000-11aa-aa11-00306543ecac": "Apple Hierarchical File System Plus (HFS+) partition ",
"7c3457ef-0000-11aa-aa11-00306543ecac": "Apple APFS container",
"55465300-0000-11aa-aa11-00306543ecac": "Apple UFS container",
"52414944-0000-11aa-aa11-00306543ecac": "Apple RAID partition",
"4c616265-6c00-11aa-aa11-00306543ecac": "Apple Label",
"53746f72-6167-11aa-aa11-00306543ecac": "Apple Core Storage Container",
"6a898cc3-1dd2-11b2-99a6-080020736631": "ZFS Partition",
"_comment_21": "Chrome OS GUIDS",
"2568845d-2332-4675-bc39-8fa5a4748d15": "Chrome OS kernel ",
"3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec": "Chrome OS rootfs ",
"2e0a753d-9e48-43b0-8337-b15192cb1b5e": "Chrome OS future use ",
"_comment_22": "Android GUIDS",
"fe3a2a5d-4f32-41a7-b725-accc3285a309": "Android Bootloader",
"114eaffe-1552-4022-b26e-9b053604cf84": "Android Bootloader 2",
"49a4d17f-93a3-45c1-a0de-f50b2ebe2599": "Android Boot",
"4177c722-9e92-4aab-8644-43502bfd5506": "Android Recovery",
"38f428e6-d326-425d-9140-6e0ea133647c": "Android System",
"bd59408b-4514-490d-bf12-9878d963f378": "Android Config",
"8f68cc74-c5e5-48da-be91-a0c8c15e9c80": "Android Factory",
"ac6d7924-eb71-4df8-b48d-e267b27148ff": "Android OEM",
"_comment_23": "MISC GUIDs",
"5023b95c-db26-429b-a648-bd47664c8012": "Built-in EFI Shell",
"610a0202-d308-00c4-0000-000004300d06": "Mystery UUID",
"00000000-0000-0000-0000-000000000000": "Empty UUID"
}
}

View File

@ -0,0 +1,36 @@
package hirs.attestationca.portal;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import java.util.Collections;
@SpringBootApplication
@EnableAutoConfiguration
@Log4j2
@ComponentScan({"hirs.attestationca.portal", "hirs.attestationca.portal.page.controllers", "hirs.attestationca.persist.entity", "hirs.attestationca.persist.service"})
public class HIRSApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(HIRSApplication.class);
}
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(HIRSApplication.class);
springApplication.setDefaultProperties(Collections.singletonMap("server.servlet.context-path", "/portal"));
springApplication.run(args);
log.debug("Debug log message");
log.info("Info log message");
log.error("Error log message");
log.warn("Warn log message");
log.fatal("Fatal log message");
log.trace("Trace log message");
}
}

View File

@ -0,0 +1,59 @@
package hirs.attestationca.portal;
import hirs.attestationca.persist.service.SettingsServiceImpl;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@WebListener
public class HIRSDbInitializer implements ServletContextListener {
@Autowired
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Autowired
static SettingsServiceImpl settingsService = new SettingsServiceImpl();
//
// public void contextInitialized(final ServletContextEvent servletContextEvent) {
//// AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// context.getEnvironment().addActiveProfile("server");
// context.register(PersistenceJPAConfig.class);
// context.refresh();
//
// // obtain reference to hibernate session factory
// EntityManager entityManager = context.getBean(EntityManagerFactory.class)
// .createEntityManager();
// /**
// * This fails if there is an entry already.
// */
//// entityManager.getTransaction().begin();
//// entityManager.persist(context.getBean("default-settings"));
//// entityManager.getTransaction().commit();
//
// insertDefaultEntries();
// }
//
// /**
// * Insert the ACA's default entries into the DB. This class is invoked after successful
// * install of the HIRS_AttestationCA RPM.
// *
// */
// public static synchronized void insertDefaultEntries() {
// LOGGER.error("Ensuring default ACA database entries are present.");
//
// // If the SupplyChainAppraiser exists, do not attempt to re-save the supply chain appraiser
// // or SupplyChainSettings
//
// // Create the SupplyChainAppraiser
// LOGGER.error("Saving supply chain appraiser...");
//
//
// // Create the SupplyChainSettings
// LOGGER.error("Saving default supply chain policy...");
//// SupplyChainSettings supplyChainPolicy = new SupplyChainSettings(
//// SupplyChainSettings.DEFAULT_POLICY);
// settingsService.saveSettings(new SupplyChainSettings("Default", "Settings are configured for no validation flags set."));
//
// LOGGER.error("ACA database initialization complete.");
// }
}

View File

@ -0,0 +1,86 @@
package hirs.attestationca.portal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:hibernate.properties" })
@ComponentScan({ "hirs.attestationca.portal.page" })
@EnableJpaRepositories(basePackages = "hirs.attestationca.persist")
public class PersistenceJPAConfig {
@Autowired
private Environment environment;
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean entityManagerBean = new LocalContainerEntityManagerFactoryBean();
entityManagerBean.setDataSource(dataSource());
entityManagerBean.setPackagesToScan(new String[] {"hirs.attestationca.persist"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerBean.setJpaVendorAdapter(vendorAdapter);
entityManagerBean.setJpaProperties(additionalProperties());
return entityManagerBean;
}
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getProperty("hibernate.connection.driver_class"));
dataSource.setUrl(environment.getProperty("hibernate.connection.url"));
dataSource.setUsername(environment.getProperty("hibernate.connection.username"));
dataSource.setPassword(environment.getProperty("hibernate.connection.password"));
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto",
environment.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect",
environment.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache",
"false");
return hibernateProperties;
}
//
// @Bean(name="default-settings")
// public SupplyChainSettings supplyChainSettings() {
// SupplyChainSettings scSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
//
// return scSettings;
// }
}

View File

@ -0,0 +1,74 @@
package hirs.attestationca.portal.datatables;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* A Wrapper for Data Table JSON responses. Allows Spring to serialize a data object with additional
* meta data required by data tables.
*
* @param <T> the type of object that is being wrapped.
*/
@NoArgsConstructor(access = AccessLevel.PUBLIC)
public final class DataTableResponse<T> {
private List<T> data = new LinkedList<T>();
@Getter @Setter
private int draw;
@Getter @Setter
private long recordsTotal, recordsFiltered;
/**
* Builds a data table response using a FilteredRecordList.
*
* @param recordList the filtered record list
* @param inputQuery the data table input (used for draw)
*/
// public DataTableResponse(final FilteredRecordsList<T> recordList,
// final DataTableInput inputQuery) {
// this(recordList, inputQuery.getDraw(),
// recordList.getRecordsTotal(), recordList.getRecordsFiltered());
// }
/**
* Constructs a data table response using the specified data with the data table specific
* information.
*
* @param data that is to be displayed by data table
* @param draw the originating draw request ID (usually from a web request)
* @param recordsTotal total number of records inside the data
* @param recordsFiltered number of records excluded from the request
*/
public DataTableResponse(final List<T> data, final int draw, final long recordsTotal,
final long recordsFiltered) {
setData(data);
this.draw = draw;
this.recordsTotal = recordsTotal;
this.recordsFiltered = recordsFiltered;
}
/**
* Gets the data table data.
*
* @return the data
*/
public List<T> getData() {
return Collections.unmodifiableList(data);
}
/**
* Sets the data table data.
*
* @param data the data
*/
public void setData(final List<T> data) {
this.data.clear();
this.data.addAll(data);
}
}

View File

@ -0,0 +1,4 @@
/**
* Root Package for HIRS Attestation CA Portal.
*/
package hirs.attestationca.portal;

View File

@ -0,0 +1,220 @@
package hirs.attestationca.portal.page;
import hirs.utils.VersionHelper;
/**
* Contains attributes required to display a portal page and its menu link.
*/
public enum Page {
/**
* Site landing page.
*/
INDEX("HIRS Attestation CA", "Version: " + VersionHelper.getVersion(),
null, false, false, null, null),
/**
* Page to import and manage trust chains.
*/
TRUST_CHAIN("Trust Chain Management", "ic_store",
null, "certificate-request/"),
/**
* Page to display and manage endorsement key credentials.
*/
ENDORSEMENT_KEY_CREDENTIALS("Endorsement Key Certificates", "ic_vpn_key",
"first", "certificate-request/"),
/**
* Page to display and manage platform credentials.
*/
PLATFORM_CREDENTIALS("Platform Certificates", "ic_important_devices",
null, "certificate-request/"),
/**
* Page to display issued certificates.
*/
ISSUED_CERTIFICATES("Issued Certificates", "ic_library_books",
null, "certificate-request/"),
/**
* Non-menu page to display certificate. Reachable from all certificate pages.
*/
CERTIFICATE_DETAILS("Certificate Details", "", null, true, false, null, null),
/**
* Page to display registered devices.
*/
DEVICES("Devices", "ic_devices", "first"),
/**
* Page to display RIMs.
*/
REFERENCE_MANIFESTS("Reference Integrity Manifests",
"ic_important_devices", "first"),
/**
* Non-menu page to display rims.
*/
RIM_DETAILS("Reference Integrity Manifest Details",
"", null, true, false, null, null),
/**
* Page to display RIM event digest table.
*/
RIM_DATABASE("RIM Database", "ic_important_devices", "first"),
/**
* Page that manages Attestation CA Policy.
*/
POLICY("Policy", "ic_subtitles"),
/**
* Help page.
*/
HELP("Help", "ic_live_help");
private final String title;
private final String subtitle;
private final String icon;
private final boolean hasMenu;
private final String menuLinkClass;
private final boolean inMenu;
private final String prefixPath;
private final String viewName;
/**
* Constructor for Page.
*
* @param title title of the page
* @param subtitle subtitle of the page
* @param icon icon for the page
* @param hasMenu the page has its own menu
* @param inMenu the page appears in a menu
* @param menuLinkClass the category to which this page belongs
* @param prefixPath prefix path that appears in the URL for this page
*/
Page(final String title,
final String subtitle,
final String icon,
final boolean hasMenu,
final boolean inMenu,
final String menuLinkClass,
final String prefixPath) {
this.title = title;
this.subtitle = subtitle;
this.icon = icon;
this.hasMenu = hasMenu;
this.menuLinkClass = menuLinkClass;
this.inMenu = inMenu;
this.prefixPath = prefixPath;
viewName = this.name().toLowerCase().replaceAll("_", "-");
}
/**
* Constructor for Page.
*
* @param title title of the page
* @param icon icon for the page
* @param menuLinkClass the category to which this page belongs
* @param prefixPath prefix path that appears in the URL for this page
*/
Page(final String title,
final String icon,
final String menuLinkClass,
final String prefixPath) {
this(title, null, icon, true, true, menuLinkClass, prefixPath);
}
/**
* Constructor for Page.
*
* @param title title of the page
* @param icon icon for the page
* @param menuLinkClass the category to which this page belongs
*/
Page(final String title,
final String icon,
final String menuLinkClass) {
this(title, null, icon, true, true, menuLinkClass, null);
}
/**
* Constructor for Page.
*
* @param title title of the page
* @param icon icon for the page
*/
Page(final String title,
final String icon) {
this(title, null, icon, true, true, null, null);
}
/**
* Returns the title of the page.
*
* @return the title of the page.
*/
public String getTitle() {
return title;
}
/**
* Returns the subtitle of the page.
*
* @return the subtitle of the page.
*/
public String getSubtitle() {
return subtitle;
}
/**
* Returns the base filename of the icon for page. E.g. "ic_my_icon", which will be appended
* with appropriate size string (_24dp/_48dp) and file extension (.png) when used.
*
* @return the base filename of the icon for page.
*/
public String getIcon() {
return icon;
}
/**
* Returns true if the page should be displayed in the navigation menu.
*
* @return true if the page should be displayed in the navigation menu.
*/
public boolean getInMenu() {
return inMenu;
}
/**
* Returns the css class to add to the menu link to display it appropriately. E.g. "first" if
* the link is the first in a group to separate it visually from the previous group.
*
* @return he class to add to the menu link to display it appropriately.
*/
public String getMenuLinkClass() {
return menuLinkClass;
}
/**
* Returns true if the page should display the navigation menu.
*
* @return true if the page should display the navigation menu.
*/
public boolean getHasMenu() {
return hasMenu;
}
/**
* Return the page's view name.
*
* @return the page's view name
*/
public String getViewName() {
return viewName;
}
/**
* Return the page's view name.
*
* @return the page's view name
*/
public String getPrefixPath() {
return prefixPath;
}
}

View File

@ -0,0 +1,169 @@
package hirs.attestationca.portal.page;
import hirs.utils.BannerConfiguration;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.http.client.utils.URIBuilder;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Optional;
/**
* Abstract class to provide common functionality for page Controllers.
*
* @param <P> PageParams class used by the subclass.
*/
@Log4j2
@AllArgsConstructor
public abstract class PageController<P extends PageParams> {
/**
* Model attribute name used by initPage for the initial data passed to the page.
*/
public static final String INITIAL_DATA = "initialData";
/**
* Reserved attribute used by page.tag to identify a page's general
* information.
*/
public static final String PAGE_ATTRIBUTE = "page";
/**
* Reserved attribute used by page.tag to identify the page collection used
* for navigation.
*/
public static final String PAGES_ATTRIBUTE = "pages";
/**
* Reserved attribute used by page.tag to identify the banner information.
*/
public static final String BANNER_ATTRIBUTE = "banner";
/**
* Reserved attribute used by page.tag to identify the messages the page
* should display.
*/
public static final String MESSAGES_ATTRIBUTE = "messages";
private final Page page;
/**
* Returns the path for the view and the data model for the page.
*
* @param params The object to map url parameters into.
* @param model The data model for the request. Can contain data from
* redirect.
* @return the path for the view and data model for the page.
*/
@RequestMapping
public abstract ModelAndView initPage(@ModelAttribute P params, Model model);
/**
* Creates a generic ModelAndView containing this page's configuration and
* the list of other pages for navigational purposes.
*
* @return A generic ModelAndView containing basic information for the page.
*/
protected final ModelAndView getBaseModelAndView() {
return getBaseModelAndView(page);
}
/**
* Creates a generic ModelAndView containing the specify page
* configuration and the list of other pages for navigational
* purposes.
*
* @param newPage new page to get the model and view
* @return A generic ModelAndView containing basic information for the page.
*/
protected final ModelAndView getBaseModelAndView(final Page newPage) {
ModelMap modelMap = new ExtendedModelMap();
// add page information
modelMap.addAttribute(PAGE_ATTRIBUTE, newPage);
// add other pages for navigation
modelMap.addAttribute(PAGES_ATTRIBUTE, Page.values());
// add banner information
try {
BannerConfiguration banner = new BannerConfiguration();
modelMap.addAttribute(BANNER_ATTRIBUTE, banner);
} catch (IOException ex) {
modelMap.addAttribute(BANNER_ATTRIBUTE, null);
}
return new ModelAndView(newPage.getViewName(), modelMap);
}
/**
* Redirects back to this controller's page with the specified data.
*
* @param params The url parameters to pass to the page.
* @param model The model data to pass to the page.
* @param attr The request's RedirectAttributes to hold the model data.
* @return RedirectView back to the page with the specified parameters.
* @throws URISyntaxException if malformed URI
*/
protected final RedirectView redirectToSelf(
final P params,
final Map<String, ?> model,
final RedirectAttributes attr) throws URISyntaxException {
return redirectTo(page, params, model, attr);
}
/**
* Redirects controller's page with the specified data.
*
* @param newPage new page to get the model and view
* @param params The url parameters to pass to the page.
* @param model The model data to pass to the page.
* @param attr The request's RedirectAttributes to hold the model data.
* @return RedirectView back to the page with the specified parameters.
* @throws URISyntaxException if malformed URI
*/
protected final RedirectView redirectTo(
final Page newPage,
final P params,
final Map<String, ?> model,
final RedirectAttributes attr) throws URISyntaxException {
String defaultUri = "../" + newPage.getViewName();
// create uri with specified parameters
URIBuilder uri = new URIBuilder("../" + newPage.getViewName());
log.debug("Redirection URI = " + uri.toString());
if (params != null) {
for (Map.Entry<String, ?> e : params.asMap().entrySet()) {
Object v = Optional.ofNullable(e.getValue()).orElse("");
uri.addParameter(e.getKey(), v.toString());
}
}
// create view
RedirectView redirect = new RedirectView(defaultUri);
// do not put model attributes in the url
redirect.setExposeModelAttributes(false);
// add model data to forward to redirected page
if (model != null) {
for (Map.Entry<String, ?> e : model.entrySet()) {
attr.addFlashAttribute(e.getKey(), e.getValue());
}
}
return redirect;
}
}

View File

@ -0,0 +1,70 @@
package hirs.attestationca.portal.page;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Encapsulates error, success, and informational messages to display on a page.
*/
public class PageMessages {
private final List<String> error = new ArrayList<>();
private final List<String> success = new ArrayList<>();
private final List<String> info = new ArrayList<>();
/**
* Returns the list of error messages.
*
* @return the list of error messages.
*/
public List<String> getError() {
return Collections.unmodifiableList(error);
}
/**
* Adds an error message.
*
* @param error the error message to add
*/
public void addError(final String error) {
this.error.add(error);
}
/**
* Returns the list of success messages.
*
* @return the list of success messages.
*/
public List<String> getSuccess() {
return Collections.unmodifiableList(success);
}
/**
* Adds a success message.
*
* @param success the success message to add
*/
public void addSuccess(final String success) {
this.success.add(success);
}
/**
* Returns the list of informational messages.
*
* @return the list of informational messages.
*/
public List<String> getInfo() {
return Collections.unmodifiableList(info);
}
/**
* Adds an informational message.
*
* @param info the informational message to add
*/
public void addInfo(final String info) {
this.info.add(info);
}
}

View File

@ -0,0 +1,17 @@
package hirs.attestationca.portal.page;
import java.util.LinkedHashMap;
/**
* Interface for a page's url parameters.
*/
public interface PageParams {
/**
* Allows PageController to iterate over the url parameters.
*
* @return map containing the object's url parameters.
*/
LinkedHashMap<String, ?> asMap();
}

View File

@ -0,0 +1,80 @@
package hirs.attestationca.portal.page;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
* PolicyPage model object to demonstrate data exchange between policy.jsp page
* form form and controller.
*/
@Setter
@Getter
@ToString
@NoArgsConstructor
public class PolicyPageModel {
// Variables to communicate policy settings to page
private boolean enableEcValidation;
private boolean enablePcCertificateValidation;
private boolean enablePcCertificateAttributeValidation;
private boolean enableFirmwareValidation;
private boolean issueAttestationCertificate;
private boolean issueDevIdCertificate;
private boolean generateOnExpiration;
private boolean devIdExpirationFlag;
private boolean enableIgnoreIma;
private boolean enableIgnoreTboot;
private boolean enableIgnoreGpt;
private boolean enableIgnoreOsEvt;
// Variables to get policy settings from page
private String pcValidate;
private String pcAttributeValidate;
private String ecValidate;
private String fmValidate;
private String attestationCertificateIssued;
private String devIdCertificateIssued;
private String generationExpirationOn;
private String devIdExpirationChecked;
private String numOfValidDays;
private String reissueThreshold;
private String devIdReissueThreshold;
private String ignoreIma;
private String ignoretBoot;
private String ignoreGpt;
private String ignoreOsEvt;
private String expirationValue;
private String devIdExpirationValue;
private String thresholdValue;
private String devIdThresholdValue;
/**
* Constructor. Sets fields from policy.
*
* @param policy The supply chain policy
*/
public PolicyPageModel(final SupplyChainSettings policy) {
this.enableEcValidation = policy.isEcValidationEnabled();
this.enablePcCertificateValidation = policy.isPcValidationEnabled();
this.enablePcCertificateAttributeValidation = policy.isPcAttributeValidationEnabled();
this.enableFirmwareValidation = policy.isFirmwareValidationEnabled();
this.issueAttestationCertificate = policy.isIssueAttestationCertificate();
this.issueDevIdCertificate = policy.isIssueDevIdCertificate();
this.generateOnExpiration = policy.isGenerateOnExpiration();
this.devIdExpirationFlag = policy.isDevIdExpirationFlag();
this.numOfValidDays = policy.getValidityDays();
this.reissueThreshold = policy.getReissueThreshold();
this.expirationValue = policy.getValidityDays();
this.thresholdValue = policy.getReissueThreshold();
this.devIdExpirationValue = policy.getDevIdValidityDays();
this.devIdReissueThreshold = policy.getDevIdReissueThreshold();
this.devIdThresholdValue = policy.getDevIdReissueThreshold();
// pcrPolicy
this.enableIgnoreIma = policy.isIgnoreImaEnabled();
this.enableIgnoreTboot = policy.isIgnoretBootEnabled();
this.enableIgnoreGpt = policy.isIgnoreGptEnabled();
this.enableIgnoreOsEvt = policy.isIgnoreOsEvtEnabled();
}
}

View File

@ -0,0 +1,119 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages;
import hirs.attestationca.portal.page.params.CertificateDetailsPageParams;
import hirs.attestationca.portal.page.utils.CertificateStringMapBuilder;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.util.HashMap;
import java.util.UUID;
/**
* Controller for the Certificate Details page.
*/
@Log4j2
@Controller
@RequestMapping("/certificate-details")
public class CertificateDetailsPageController extends PageController<CertificateDetailsPageParams> {
/**
* Model attribute name used by initPage for the initial data passed to the page.
*/
static final String INITIAL_DATA = "initialData";
private final CertificateServiceImpl certificateServiceImpl;
/**
* Constructor providing the Page's display and routing specification.
* @param certificateServiceImpl the certificate manager
*/
@Autowired
public CertificateDetailsPageController(final CertificateServiceImpl certificateServiceImpl) {
super(Page.CERTIFICATE_DETAILS);
this.certificateServiceImpl = certificateServiceImpl;
}
/**
* Returns the path for the view and the data model for the page.
*
* @param params The object to map url parameters into.
* @param model The data model for the request. Can contain data from redirect.
* @return the path for the view and data model for the page.
*/
@Override
@RequestMapping
public ModelAndView initPage(final CertificateDetailsPageParams params, final Model model) {
// get the basic information to render the page
ModelAndView mav = getBaseModelAndView();
PageMessages messages = new PageMessages();
// Map with the certificate information
HashMap<String, Object> data = new HashMap<>();
// Check if parameters were set
if (params.getId() == null) {
String typeError = "ID was not provided";
messages.addError(typeError);
log.error(typeError);
mav.addObject(MESSAGES_ATTRIBUTE, messages);
} else if (params.getType() == null) {
String typeError = "Type was not provided";
messages.addError(typeError);
log.error(typeError);
mav.addObject(MESSAGES_ATTRIBUTE, messages);
} else {
try {
String type = params.getType().toLowerCase();
UUID uuid = UUID.fromString(params.getId());
switch (type) {
case "certificateauthority":
data.putAll(CertificateStringMapBuilder.getCertificateAuthorityInformation(
uuid, certificateServiceImpl));
break;
case "endorsement":
data.putAll(CertificateStringMapBuilder.getEndorsementInformation(uuid,
certificateServiceImpl));
break;
case "platform":
data.putAll(CertificateStringMapBuilder.getPlatformInformation(uuid,
certificateServiceImpl));
break;
case "issued":
data.putAll(CertificateStringMapBuilder.getIssuedInformation(uuid,
certificateServiceImpl));
break;
default:
String typeError = "Invalid certificate type: " + params.getType();
messages.addError(typeError);
log.error(typeError);
mav.addObject(MESSAGES_ATTRIBUTE, messages);
break;
}
} catch (IllegalArgumentException | IOException ex) {
String uuidError = "Failed to parse ID from: " + params.getId();
messages.addError(uuidError);
log.error(uuidError, ex);
}
if (data.isEmpty()) {
String notFoundMessage = "Unable to find certificate with ID: " + params.getId();
messages.addError(notFoundMessage);
log.warn(notFoundMessage);
mav.addObject(MESSAGES_ATTRIBUTE, messages);
} else {
mav.addObject(INITIAL_DATA, data);
}
}
// return the model and view
return mav;
}
}

View File

@ -0,0 +1,73 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Log4j2
@Controller
@RequestMapping("/certificate-request")
public class CertificatePageController extends PageController<NoPageParams> {
private final CertificateServiceImpl certificateServiceImpl;
private CertificateAuthorityCredential certificateAuthorityCredential;
private static final String TRUSTCHAIN = "trust-chain";
private static final String PLATFORMCREDENTIAL = "platform-credentials";
private static final String ENDORSEMENTCREDENTIAL = "endorsement-key-credentials";
private static final String ISSUEDCERTIFICATES = "issued-certificates";
/**
* Model attribute name used by initPage for the aca cert info.
*/
static final String ACA_CERT_DATA = "acaCertData";
/**
* Constructor providing the Page's display and routing specification.
*
* @param certificateServiceImpl the certificate manager
* @param crudManager the CRUD manager for certificates
* @param acaCertificate the ACA's X509 certificate
*/
@Autowired
public CertificatePageController(
final CertificateServiceImpl certificateServiceImpl
// final CrudManager<Certificate> crudManager,
// final X509Certificate acaCertificate
) {
super(Page.TRUST_CHAIN);
this.certificateServiceImpl = certificateServiceImpl;
// this.dataTableQuerier = crudManager;
// try {
//// certificateAuthorityCredential
//// = new CertificateAuthorityCredential(acaCertificate.getEncoded());
// } catch (IOException e) {
// log.error("Failed to read ACA certificate", e);
// } catch (CertificateEncodingException e) {
// log.error("Error getting encoded ACA certificate", e);
// }
}
/**
* Returns the path for the view and the data model for the page.
*
* @param params The object to map url parameters into.
* @param model The data model for the request. Can contain data from
* redirect.
* @return the path for the view and data model for the page.
*/
@Override
@RequestMapping
public ModelAndView initPage(final NoPageParams params, final Model model) {
return getBaseModelAndView();
}
}

View File

@ -0,0 +1,60 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.persist.service.DeviceServiceImpl;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/devices")
public class DevicePageController extends PageController<NoPageParams> {
/**
* https://odrotbohm.de/2013/11/why-field-injection-is-evil/
*
* Autowiring property vs constructor
*/
private final DeviceServiceImpl deviceServiceImpl;
private final DeviceRepository deviceRepository;
@Autowired
public DevicePageController(DeviceServiceImpl deviceServiceImpl,
DeviceRepository deviceRepository) {
super(Page.DEVICES);
this.deviceServiceImpl = deviceServiceImpl;
this.deviceRepository = deviceRepository;
}
@Override
@RequestMapping
public ModelAndView initPage(final NoPageParams params, final Model model) {
return getBaseModelAndView();
}
// @RequestMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE,
// method = RequestMethod.GET)
// public DataTableResponse<HashMap<String, Object>> getTableData(
// final DataTableInput input) {
// String orderColumnName = input.getOrderColumnName();
// FilteredRecordsList<HashMap<String, Object>> record
// = retrieveDevicesAndAssociatedCertificates(deviceList);
// modelMap.put("devices", deviceServiceImpl.retrieveDevices());
// return new DataTableResponse<>(record, input);
// }
@GetMapping(path="/all")
public @ResponseBody Iterable<Device> getAllDevices() {
return deviceRepository.findAll();
}
}

View File

@ -0,0 +1,23 @@
package hirs.attestationca.portal.page.controllers;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@Controller("error")
public class ErrorController {
@ExceptionHandler(Exception.class)
public ModelAndView handleException(HttpServletRequest request, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("exception", ex.getLocalizedMessage());
modelAndView.addObject("url", request.getRequestURL());
modelAndView.setViewName("error");
return modelAndView;
}
}

View File

@ -0,0 +1,42 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@Log4j2
@RequestMapping("/index")
public class IndexPageController extends PageController<NoPageParams> {
/**
* Constructor providing the Page's display and routing specification.
*/
public IndexPageController() {
super(Page.INDEX);
}
/**
* Returns the path for the view and the data model for the page.
*
* @param params The object to map url parameters into.
* @param model The data model for the request. Can contain data from redirect.
* @return the path for the view and data model for the page.
*/
@Override
@RequestMapping
public ModelAndView initPage(final NoPageParams params, final Model model) {
return getBaseModelAndView();
}
// @RequestMapping(value = "/", method = RequestMethod.GET)
// public String showIndexPage(ModelMap model) {
// model.put("name", "welcome");
// return "welcome";
// }
}

View File

@ -0,0 +1,21 @@
package hirs.attestationca.portal.page.controllers;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Log4j2
public class LombokLoggingController {
@RequestMapping("/lombok")
public String index() {
log.trace("A TRACE Message");
log.debug("A DEBUG Message");
log.info("An INFO Message");
log.warn("A WARN Message");
log.error("An ERROR Message");
return "Howdy! Check out the Logs to see the output...";
}
}

View File

@ -0,0 +1,962 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import hirs.attestationca.persist.service.SettingsServiceImpl;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages;
import hirs.attestationca.portal.page.PolicyPageModel;
import hirs.attestationca.portal.page.params.NoPageParams;
import hirs.utils.exception.PolicyManagerException;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
/**
* Controller for the Policy page.
*/
@Log4j2
@Controller
@RequestMapping("/policy")
public class PolicyPageController extends PageController<NoPageParams> {
/**
* Represents a web request indicating to enable a setting (based on radio
* buttons from a web form).
*/
private static final String ENABLED_CHECKED_PARAMETER_VALUE = "checked";
private static final String ENABLED_EXPIRES_PARAMETER_VALUE = "expires";
private SettingsServiceImpl settingsService;
/**
* Model attribute name used by initPage for the initial data passed to the
* page.
*/
public static final String INITIAL_DATA = "initialData";
/**
* Flash attribute name used by initPage and post for the data forwarded
* during the redirect from the POST operation back to the page.
*/
public static final String RESULT_DATA = "resultData";
/**
* Constructor.
*
* @param policyService the policy service
*/
@Autowired
public PolicyPageController(final SettingsServiceImpl policyService) {
super(Page.POLICY);
this.settingsService = policyService;
if (this.settingsService.getByName("Default") == null) {
this.settingsService.saveSettings(new SupplyChainSettings("Default", "Settings are configured for no validation flags set."));
}
}
/**
* Returns the path for the view and the data model for the page.
*
* @param params The object to map url parameters into.
* @param model The data model for the request. Can contain data from
* redirect.
* @return the path for the view and data model for the page.
*/
@Override
@RequestMapping
public ModelAndView initPage(final NoPageParams params, final Model model) {
// get the basic information to render the page
ModelAndView mav = getBaseModelAndView();
SupplyChainSettings policy = getDefaultPolicy();
log.debug(policy);
PolicyPageModel pageModel = new PolicyPageModel(policy);
mav.addObject(INITIAL_DATA, pageModel);
log.debug(pageModel);
return mav;
}
/**
* Updates the Platform Cert Validation policy setting and redirects back to
* the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-pc-validation", method = RequestMethod.POST)
public RedirectView updatePcVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr) throws URISyntaxException {
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean pcValidationOptionEnabled
= ppModel.getPcValidate().equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
// If PC policy setting change results in invalid policy, inform user
if (!isPolicyValid(policy.isEcValidationEnabled(), pcValidationOptionEnabled,
policy.isPcAttributeValidationEnabled())) {
handleUserError(model, messages,
"Unable to change Platform Validation setting,"
+ " invalid policy configuration.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create display message
if (pcValidationOptionEnabled) {
policy.setPcValidationEnabled(true);
successMessage = "Platform certificate validation enabled";
} else {
policy.setPcValidationEnabled(false);
policy.setPcAttributeValidationEnabled(false);
successMessage = "Platform certificate validation disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
// Log and return any error messages to the user
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA platform validation Policy",
"Error updating policy. \n" + pmEx.getMessage());
}
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the Platform Cert Attribute Validation policy setting and
* redirects back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-pc-attribute-validation", method = RequestMethod.POST)
public RedirectView updatePcAttributeVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean pcAttributeValidationOptionEnabled = ppModel.getPcAttributeValidate()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
// If PC Attribute Validation is enabled without PC Validation, disallow change
if (!isPolicyValid(policy.isEcValidationEnabled(),
policy.isPcValidationEnabled(), pcAttributeValidationOptionEnabled)) {
handleUserError(model, messages,
"To enable Platform Attribute Validation, Platform Credential Validation"
+ " must also be enabled.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create display message
if (pcAttributeValidationOptionEnabled) {
policy.setPcAttributeValidationEnabled(true);
successMessage = "Platform certificate attribute validation enabled";
} else {
policy.setPcAttributeValidationEnabled(false);
successMessage = "Platform certificate attribute validation disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
// Log and return any error messages to the user
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA platform certificate attribute validation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the Attestation Certificate generation policy setting and redirects
* back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-issue-attestation", method = RequestMethod.POST)
public RedirectView updateAttestationVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean issuedAttestationOptionEnabled
= ppModel.getAttestationCertificateIssued()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
if (issuedAttestationOptionEnabled) {
successMessage = "Attestation Certificate generation enabled.";
} else {
successMessage = "Attestation Certificate generation disabled.";
policy.setGenerateOnExpiration(false);
}
policy.setIssueAttestationCertificate(issuedAttestationOptionEnabled);
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA Attestation Certificate generation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the DevID Certificate generation policy setting and redirects
* back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-issue-devid", method = RequestMethod.POST)
public RedirectView updateDevIdVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean issuedDevIdOptionEnabled
= ppModel.getDevIdCertificateIssued()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
if (issuedDevIdOptionEnabled) {
successMessage = "DevID Certificate generation enabled.";
} else {
successMessage = "DevID Certificate generation disabled.";
policy.setDevIdExpirationFlag(false);
}
policy.setIssueDevIdCertificate(issuedDevIdOptionEnabled);
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA DevID Certificate generation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the state of the policy setting that indicates that the generation
* will occur in a set time frame and redirects
* back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-expire-on", method = RequestMethod.POST)
public RedirectView updateExpireOnVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
String numOfDays;
boolean generateCertificateEnabled = false;
// because this is just one option, there is not 'unchecked' value, so it is either
// 'checked' or null
if (ppModel.getGenerationExpirationOn() != null) {
generateCertificateEnabled
= ppModel.getGenerationExpirationOn()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedAttestationOptionEnabled
= policy.isIssueAttestationCertificate();
if (issuedAttestationOptionEnabled) {
if (generateCertificateEnabled) {
successMessage = "Attestation Certificate generation expiration time enabled.";
} else {
successMessage = "Attestation Certificate generation expiration time disabled.";
}
if (generateCertificateEnabled) {
numOfDays = ppModel.getExpirationValue();
if (numOfDays == null) {
numOfDays = SupplyChainSettings.TEN_YEARS;
}
} else {
numOfDays = policy.getValidityDays();
}
policy.setValidityDays(numOfDays);
} else {
generateCertificateEnabled = false;
successMessage = "Attestation Certificate generation is disabled, "
+ "can not set time expiration";
}
policy.setGenerateOnExpiration(generateCertificateEnabled);
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA Attestation Certificate generation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the state of the policy setting that indicates that the generation
* will occur in a set time frame and redirects
* back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-devid-expire-on", method = RequestMethod.POST)
public RedirectView updateDevIdExpireOnVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
String numOfDays;
boolean generateDevIdCertificateEnabled = false;
// because this is just one option, there is not 'unchecked' value, so it is either
// 'checked' or null
if (ppModel.getDevIdExpirationChecked() != null) {
generateDevIdCertificateEnabled
= ppModel.getDevIdExpirationChecked()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedDevIdOptionEnabled
= policy.isIssueDevIdCertificate();
if (issuedDevIdOptionEnabled) {
if (generateDevIdCertificateEnabled) {
successMessage = "DevID Certificate generation expiration time enabled.";
} else {
successMessage = "DevID Certificate generation expiration time disabled.";
}
if (generateDevIdCertificateEnabled) {
numOfDays = ppModel.getDevIdExpirationValue();
if (numOfDays == null) {
numOfDays = SupplyChainSettings.TEN_YEARS;
}
} else {
numOfDays = policy.getDevIdValidityDays();
}
policy.setDevIdValidityDays(numOfDays);
} else {
generateDevIdCertificateEnabled = false;
successMessage = "DevID Certificate generation is disabled, "
+ "can not set time expiration";
}
policy.setDevIdExpirationFlag(generateDevIdCertificateEnabled);
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA DevID Certificate generation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the state of the policy setting that indicates that the generation
* will occur in a set time frame from the end validity date and redirects
* back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-threshold", method = RequestMethod.POST)
public RedirectView updateThresholdVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
String threshold;
boolean generateCertificateEnabled = false;
// because this is just one option, there is not 'unchecked' value, so it is either
// 'checked' or null
if (ppModel.getGenerationExpirationOn() != null) {
generateCertificateEnabled
= ppModel.getGenerationExpirationOn()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedAttestationOptionEnabled
= policy.isIssueAttestationCertificate();
if (issuedAttestationOptionEnabled) {
if (generateCertificateEnabled) {
successMessage = "Attestation Certificate generation threshold time enabled.";
} else {
successMessage = "Attestation Certificate generation threshold time disabled.";
}
if (generateCertificateEnabled) {
threshold = ppModel.getThresholdValue();
} else {
threshold = ppModel.getReissueThreshold();
}
if (threshold == null || threshold.isEmpty()) {
threshold = SupplyChainSettings.YEAR;
}
policy.setReissueThreshold(threshold);
} else {
generateCertificateEnabled = false;
successMessage = "Attestation Certificate generation is disabled, "
+ "can not set time expiration";
}
policy.setGenerateOnExpiration(generateCertificateEnabled);
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA Attestation Certificate generation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the state of the policy setting that indicates that the generation
* will occur in a set time frame from the end validity date and redirects
* back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-devid-threshold", method = RequestMethod.POST)
public RedirectView updateDevIdThresholdVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
String threshold;
boolean generateDevIdCertificateEnabled = false;
// because this is just one option, there is not 'unchecked' value, so it is either
// 'checked' or null
if (ppModel.getDevIdExpirationChecked() != null) {
generateDevIdCertificateEnabled
= ppModel.getDevIdExpirationChecked()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedDevIdOptionEnabled
= policy.isIssueDevIdCertificate();
if (issuedDevIdOptionEnabled) {
if (generateDevIdCertificateEnabled) {
successMessage = "DevID Certificate generation threshold time enabled.";
} else {
successMessage = "DevID Certificate generation threshold time disabled.";
}
if (generateDevIdCertificateEnabled) {
threshold = ppModel.getDevIdThresholdValue();
} else {
threshold = ppModel.getDevIdReissueThreshold();
}
if (threshold == null || threshold.isEmpty()) {
threshold = SupplyChainSettings.YEAR;
}
policy.setDevIdReissueThreshold(threshold);
} else {
generateDevIdCertificateEnabled = false;
successMessage = "DevID Certificate generation is disabled, "
+ "can not set time expiration";
}
policy.setDevIdExpirationFlag(generateDevIdCertificateEnabled);
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA DevID Certificate generation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the Endorsement Credential Validation policy setting and
* redirects back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-ec-validation", method = RequestMethod.POST)
public RedirectView updateEcVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr) throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean ecValidationOptionEnabled
= ppModel.getEcValidate().equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If PC Validation is enabled without EC Validation, disallow change
if (!isPolicyValid(ecValidationOptionEnabled, policy.isPcValidationEnabled(),
policy.isPcAttributeValidationEnabled())) {
handleUserError(model, messages,
"To disable Endorsement Credential Validation, Platform Validation"
+ " must also be disabled.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create success message
if (ecValidationOptionEnabled) {
policy.setEcValidationEnabled(true);
successMessage = "Endorsement credential validation enabled";
} else {
policy.setEcValidationEnabled(false);
successMessage = "Endorsement credential validation disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA endorsement validation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the Firmware Validation policy setting and
* redirects back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-firmware-validation", method = RequestMethod.POST)
public RedirectView updateFirmwareVal(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr) throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean firmwareValidationOptionEnabled = ppModel.getFmValidate()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If firmware is enabled without PC attributes, disallow change
if (firmwareValidationOptionEnabled && !policy.isPcAttributeValidationEnabled()) {
handleUserError(model, messages,
"Firmware validation can not be "
+ "enabled without PC Attributes policy enabled.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create success message
if (firmwareValidationOptionEnabled) {
policy.setFirmwareValidationEnabled(true);
policy.setIgnoreGptEnabled(true);
successMessage = "Firmware validation enabled";
} else {
policy.setFirmwareValidationEnabled(false);
policy.setIgnoreImaEnabled(false);
policy.setIgnoretBootEnabled(false);
policy.setIgnoreOsEvtEnabled(false);
successMessage = "Firmware validation disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA firmware validation policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the ignore IMA policy setting and
* redirects back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-ima-ignore", method = RequestMethod.POST)
public RedirectView updateIgnoreIma(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr) throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean ignoreImaOptionEnabled = ppModel.getIgnoreIma()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore IMA is enabled without firmware, disallow change
if (ignoreImaOptionEnabled && !policy.isFirmwareValidationEnabled()) {
handleUserError(model, messages,
"Ignore IMA can not be "
+ "enabled without Firmware Validation policy enabled.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create success message
if (ignoreImaOptionEnabled) {
policy.setIgnoreImaEnabled(true);
successMessage = "Ignore IMA enabled";
} else {
policy.setIgnoreImaEnabled(false);
successMessage = "Ignore IMA disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA IMA ignore policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the ignore TBoot policy setting and
* redirects back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-tboot-ignore", method = RequestMethod.POST)
public RedirectView updateIgnoreTboot(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr) throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean ignoreTbootOptionEnabled = ppModel.getIgnoretBoot()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore TBoot is enabled without firmware, disallow change
if (ignoreTbootOptionEnabled && !policy.isFirmwareValidationEnabled()) {
handleUserError(model, messages,
"Ignore TBoot can not be "
+ "enabled without Firmware Validation policy enabled.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create success message
if (ignoreTbootOptionEnabled) {
policy.setIgnoretBootEnabled(true);
successMessage = "Ignore TBoot enabled";
} else {
policy.setIgnoretBootEnabled(false);
successMessage = "Ignore TBoot disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA TBoot ignore policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the ignore GPT policy setting and
* redirects back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-gpt-ignore", method = RequestMethod.POST)
public RedirectView updateIgnoreGptEvents(@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr) throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean ignoreGptOptionEnabled = ppModel.getIgnoreGpt()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore TBoot is enabled without firmware, disallow change
if (ignoreGptOptionEnabled && !policy.isFirmwareValidationEnabled()) {
handleUserError(model, messages,
"Ignore GPT Events can not be "
+ "enabled without Firmware Validation policy enabled.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create success message
if (ignoreGptOptionEnabled) {
policy.setIgnoreGptEnabled(true);
successMessage = "Ignore GPT enabled";
} else {
policy.setIgnoreGptEnabled(false);
successMessage = "Ignore GPT disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA GPT ignore policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
/**
* Updates the ignore Os Events policy setting and
* redirects back to the original page.
*
* @param ppModel The data posted by the form mapped into an object.
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return View containing the url and parameters
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "update-os-evt-ignore", method = RequestMethod.POST)
public RedirectView updateIgnoreOsEvents(
@ModelAttribute final PolicyPageModel ppModel,
final RedirectAttributes attr)
throws URISyntaxException {
// set the data received to be populated back into the form
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String successMessage;
boolean ignoreOsEvtOptionEnabled = ppModel.getIgnoreOsEvt()
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore TBoot is enabled without firmware, disallow change
if (ignoreOsEvtOptionEnabled && !policy.isFirmwareValidationEnabled()) {
handleUserError(model, messages,
"Ignore Os Events can not be "
+ "enabled without Firmware Validation policy enabled.");
return redirectToSelf(new NoPageParams(), model, attr);
}
// set the policy option and create success message
if (ignoreOsEvtOptionEnabled) {
policy.setIgnoreOsEvtEnabled(true);
policy.setIgnoreGptEnabled(true);
successMessage = "Ignore OS Events enabled";
} else {
policy.setIgnoreOsEvtEnabled(false);
successMessage = "Ignore OS Events disabled";
}
savePolicyAndApplySuccessMessage(ppModel, model, messages, successMessage, policy);
} catch (PolicyManagerException pmEx) {
handlePolicyManagerUpdateError(model, messages, pmEx,
"Error changing ACA OS Events ignore policy",
"Error updating policy. \n" + pmEx.getMessage());
}
// return the redirect
return redirectToSelf(new NoPageParams(), model, attr);
}
private void handlePolicyManagerUpdateError(final Map<String, Object> model,
final PageMessages messages,
final PolicyManagerException pmEx,
final String message, final String error) {
log.error(message, pmEx);
messages.addError(error);
model.put(MESSAGES_ATTRIBUTE, messages);
}
private void handleUserError(final Map<String, Object> model,
final PageMessages messages,
final String errorMessage) {
messages.addError(errorMessage);
model.put(MESSAGES_ATTRIBUTE, messages);
}
/**
* Takes in policy setting states and determines if policy configuration is
* valid or not. PC Attribute Validation must have PC Validation Enabled PC
* Validation must have EC Validation enabled
*
* @param isEcEnable EC Validation Policy State
* @param isPcEnable PC Validation Policy State
* @param isPcAttEnable PC Attribute Validation Policy State
* @return True if policy combination is valid
*/
private static boolean isPolicyValid(final boolean isEcEnable, final boolean isPcEnable,
final boolean isPcAttEnable) {
if (isPcAttEnable && !isPcEnable) {
return false;
} else {
return !isPcEnable || isEcEnable;
}
}
/**
* Helper function to get a fresh load of the default policy from the DB.
*
* @return The default Supply Chain Policy
*/
private SupplyChainSettings getDefaultPolicy() {
SupplyChainSettings defaultSettings = this.settingsService.getByName("Default");
if (defaultSettings == null) {
defaultSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
}
return defaultSettings;
}
/**
* Gets the default policy and applies the current values in to the page
* model.
*
* @param ppModel the page model
* @param model the map of string messages to be displayed on the view
* @return The default Supply Chain Policy
*/
private SupplyChainSettings getDefaultPolicyAndSetInModel(
final PolicyPageModel ppModel, final Map<String, Object> model) {
// load the current default policy from the DB
SupplyChainSettings policy = getDefaultPolicy();
// set the data received to be populated back into the form
model.put(RESULT_DATA, ppModel);
return policy;
}
private void savePolicyAndApplySuccessMessage(
final PolicyPageModel ppModel, final Map<String, Object> model,
final PageMessages messages, final String successMessage,
final SupplyChainSettings settings) {
// save the policy to the DB
settingsService.updateSettings(settings);
// Log and set the success message
messages.addSuccess(successMessage);
log.debug("ACA Policy set to: " + ppModel.toString());
model.put(MESSAGES_ATTRIBUTE, messages);
}
}

View File

@ -0,0 +1,59 @@
package hirs.attestationca.portal.page.params;
import hirs.attestationca.portal.page.PageParams;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.util.LinkedHashMap;
/**
* URL parameters object for the CertificateDetails page and controller.
*/
@Getter
@Setter
@AllArgsConstructor
public class CertificateDetailsPageParams implements PageParams {
private String id;
private String type;
/**
* Constructor to set ID Certificate Details URL parameters.
*
* @param id the String parameter to set
*/
public CertificateDetailsPageParams(final String id) {
this.id = id;
}
/**
* Default constructor for Spring.
*/
public CertificateDetailsPageParams() {
id = null;
type = null;
}
/**
* Allows PageController to iterate over the url parameters.
*
* @return map containing the object's URL parameters.
*/
@Override
public LinkedHashMap<String, ?> asMap() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("id", id);
map.put("type", type);
return map;
}
@Override
public String toString() {
return "CertificateDetailsPageParams{"
+ "id:' " + id + "',"
+ "type: " + type
+ "}";
}
}

View File

@ -0,0 +1,21 @@
package hirs.attestationca.portal.page.params;
import hirs.attestationca.portal.page.PageParams;
import java.util.LinkedHashMap;
/**
* Minimal implementation of PageParams for pages that do not have url parameters.
*/
public class NoPageParams implements PageParams {
/**
* Returns empty map so when iteration is required, nothing happens.
*
* @return empty map.
*/
@Override
public LinkedHashMap<String, ?> asMap() {
return new LinkedHashMap<>();
}
}

View File

@ -0,0 +1,39 @@
package hirs.attestationca.portal.page.params;
import hirs.attestationca.portal.page.PageParams;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.LinkedHashMap;
/**
* URL parameters object for the Reference Manifest Details page and controller.
*/
@NoArgsConstructor
@AllArgsConstructor
public class ReferenceManifestDetailsPageParams implements PageParams {
@Getter @Setter
private String id;
/**
* Allows PageController to iterate over the url parameters.
*
* @return map containing the object's URL parameters.
*/
@Override
public LinkedHashMap<String, ?> asMap() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("id", id);
return map;
}
@Override
public String toString() {
return "ReferenceManifestDetailsPageParams{"
+ "id:' " + id
+ "}";
}
}

View File

@ -0,0 +1,44 @@
package hirs.attestationca.portal.page.params;
import hirs.attestationca.portal.page.PageParams;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.LinkedHashMap;
/**
* URL parameters object for the ReferenceManifest page and controller.
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ReferenceManifestPageParams implements PageParams {
private String id;
private String type;
/**
*Constructor to set all Reference Integrity Manifest URL parameters.
*
* @param id the String parameter to set
*/
public ReferenceManifestPageParams(final String id) {
this.id = id;
}
/**
* Allows PageController to iterate over the url parameters.
*
* @return map containing the object's URL parameters.
*/
@Override
public LinkedHashMap<String, ?> asMap() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("id", id);
map.put("type", type);
return map;
}
}

View File

@ -0,0 +1 @@
package hirs.attestationca.portal.page.params;

View File

@ -0,0 +1,170 @@
package hirs.attestationca.portal.page.utils;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* Utility class for mapping certificate information in to string maps. These are used to display
* information on a web page, as X509 cert classes do not serialize to JSON
*/
@Log4j2
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class CertificateStringMapBuilder {
/**
* Returns the general information.
*
* @param certificate certificate to get the general information.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @return a hash map with the general certificate information.
*/
public static HashMap<String, String> getGeneralCertificateInfo(
final Certificate certificate, final CertificateServiceImpl certificateServiceImpl) {
HashMap<String, String> data = new HashMap<>();
return data;
}
/**
* Recursive function that check if all the certificate chain is present.
*
* @param certificate certificate to get the issuer
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @return a boolean indicating if it has the full chain or not.
*/
public static Certificate containsAllChain(
final Certificate certificate,
final CertificateServiceImpl certificateServiceImpl) {
Set<CertificateAuthorityCredential> issuerCertificates = new HashSet<>();
CertificateAuthorityCredential skiCA = null;
String issuerResult;
return null;
}
/**
* Returns the Certificate Authority information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getCertificateAuthorityInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl) {
// CertificateAuthorityCredential certificate =
// CertificateAuthorityCredential
// .select(certificateManager)
// .byEntityId(uuid)
// .getCertificate();
String notFoundMessage = "Unable to find Certificate Authority "
+ "Credential with ID: " + uuid;
// return getCertificateAuthorityInfoHelper(certificateServiceImpl, certificate, notFoundMessage);
return null;
}
/**
* Returns the Trust Chain credential information.
*
* @param certificate the certificate
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getCertificateAuthorityInformation(
final CertificateAuthorityCredential certificate,
final CertificateServiceImpl certificateServiceImpl) {
// return getCertificateAuthorityInfoHelper(certificateManager, certificate,
// "No cert provided for mapping");
return null;
}
private static HashMap<String, String> getCertificateAuthorityInfoHelper(
final CertificateServiceImpl certificateServiceImpl,
final CertificateAuthorityCredential certificate, final String notFoundMessage) {
HashMap<String, String> data = new HashMap<>();
return data;
}
/**
* Returns the endorsement credential information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getEndorsementInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl) {
HashMap<String, String> data = new HashMap<>();
return data;
}
/**
* Returns the Platform credential information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
* @throws IOException when parsing the certificate
* @throws IllegalArgumentException invalid argument on parsing the certificate
*/
public static HashMap<String, Object> getPlatformInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl)
throws IllegalArgumentException, IOException {
HashMap<String, Object> data = new HashMap<>();
return data;
}
/**
* Returns a HasHMap of a string.
* Ex: input "TPMSpecification{family='abc',level=0, revision=0}"
* output map[TPMSpecificationFamily] = 'abc'
* map[TPMSpecificationLevel] = 0
* map[TPMSpecificationRevision] = 0
*
* @param str HashMap string to be converted.
* @return a hash map with key-value pairs from the string
*/
private static HashMap<String, String> convertStringToHash(final String str) {
HashMap<String, String> map = new HashMap<>();
String name = str.substring(0, str.indexOf('{')).trim();
String data = str.trim().substring(str.trim().indexOf('{') + 1,
str.trim().length() - 1);
// Separate key and value and parse the key
for (String pair : data.split(",")) {
String[] keyValue = pair.split("=");
// Remove white space and change first character in the key to uppercase
keyValue[0] = Character.toUpperCase(
keyValue[0].trim().charAt(0)) + keyValue[0].trim().substring(1);
map.put(name + keyValue[0], keyValue[1].trim());
}
return map;
}
/**
* Returns the Issued Attestation Certificate information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getIssuedInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl) {
HashMap<String, String> data = new HashMap<>();
return data;
}
}

View File

@ -0,0 +1,191 @@
package hirs.attestationca.portal.page.utils;
import com.github.marandus.pciid.model.Device;
import com.github.marandus.pciid.model.Vendor;
import com.github.marandus.pciid.service.PciIdsDatabase;
import com.google.common.base.Strings;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.bouncycastle.asn1.DERUTF8String;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Provide Java access to PCI IDs.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class PciIds {
/**
* This pci ids file can be in different places on different distributions.
*/
public static final List<String> PCI_IDS_PATH =
Collections.unmodifiableList(new ArrayList<>() {
private static final long serialVersionUID = 1L;
{
add("/usr/share/hwdata/pci.ids");
add("/usr/share/misc/pci.ids");
add("/tmp/pci.ids");
}
});
/**
* The PCI IDs Database object.
*
* This only needs to be loaded one time.
*
* The pci ids library protects the data inside the object by making it immutable.
*/
public static final PciIdsDatabase DB = new PciIdsDatabase();
static {
if (!DB.isReady()) {
String dbFile = null;
for (final String path : PCI_IDS_PATH) {
if ((new File(path)).exists()) {
dbFile = path;
break;
}
}
if (dbFile != null) {
InputStream is = null;
try {
is = new FileInputStream(new File(dbFile));
DB.loadStream(is);
} catch (IOException e) {
// DB will not be ready, hardware IDs will not be translated
dbFile = null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
dbFile = null;
}
}
}
}
}
}
/**
* The Component Class TCG Registry OID.
*/
public static final String COMPCLASS_TCG_OID = "2.23.133.18.3.1";
/**
* The Component Class Value mask for NICs.
*/
public static final String COMPCLASS_TCG_CAT_NIC = "00090000";
/**
* The Component Class Value mask for GFX cards.
*/
public static final String COMPCLASS_TCG_CAT_GFX = "00050000";
/**
* Iterate through all components and translate PCI hardware IDs as necessary. It will only
* translate ComponentIdentifierV2+ objects as it relies on Component Class information.
* @param components List of ComponentIdentifiers.
* @return the translated list of ComponentIdentifiers.
*/
public static List<ComponentIdentifier> translate(
final List<ComponentIdentifier> components) {
List<ComponentIdentifier> newList = new ArrayList<>();
if (components != null && !components.isEmpty()) {
for (final ComponentIdentifier component : components) {
// V2 components should not be found alongside V1 components
// they pass through just in case
if (component.isVersion2()) {
newList.add(translate((ComponentIdentifierV2) component));
} else {
newList.add(component);
}
}
}
return newList;
}
/**
* Translate Vendor and Device IDs, if found, in ComponentIdentifierV2 objects.
* It will only translate ID values, any other value will pass through.
* @param component ComponentIdentifierV2 object.
* @return the translated ComponentIdentifierV2 object.
*/
public static ComponentIdentifierV2 translate(final ComponentIdentifierV2 component) {
ComponentIdentifierV2 newComponent = null;
if (component != null) {
newComponent = component;
// This can be updated as we get more accurate component class registries and values
// Component Class Registry not accessible: TCG assumed
final String compClassValue = component.getComponentClass().getCategory();
if (compClassValue.equals(COMPCLASS_TCG_CAT_NIC)
|| compClassValue.equals(COMPCLASS_TCG_CAT_GFX)) {
DERUTF8String manufacturer = translateVendor(component.getComponentManufacturer());
DERUTF8String model = translateDevice(component.getComponentManufacturer(),
component.getComponentModel());
newComponent = new ComponentIdentifierV2(component.getComponentClass(),
manufacturer,
model,
component.getComponentSerial(),
component.getComponentRevision(),
component.getComponentManufacturerId(),
component.getFieldReplaceable(),
component.getComponentAddress(),
component.getCertificateIdentifier(),
component.getComponentPlatformUri(),
component.getAttributeStatus());
}
}
return newComponent;
}
/**
* 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 DERUTF8String, likely from a ComponentIdentifier
* @return DERUTF8String with the discovered vendor name, or the original manufacturer value.
*/
public static DERUTF8String translateVendor(final DERUTF8String refManufacturer) {
DERUTF8String manufacturer = refManufacturer;
if (manufacturer != null && manufacturer.getString().trim().matches("^[0-9A-Fa-f]{4}$")) {
Vendor ven = DB.findVendor(manufacturer.getString().toLowerCase());
if (ven != null && !Strings.isNullOrEmpty(ven.getName())) {
manufacturer = new DERUTF8String(ven.getName());
}
}
return manufacturer;
}
/**
* 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 DERUTF8String, likely from a ComponentIdentifier
* @param refModel DERUTF8String, likely from a ComponentIdentifier
* @return DERUTF8String with the discovered device name, or the original model value.
*/
public static DERUTF8String translateDevice(final DERUTF8String refManufacturer,
final DERUTF8String refModel) {
DERUTF8String manufacturer = refManufacturer;
DERUTF8String model = refModel;
if (manufacturer != null
&& model != null
&& manufacturer.getString().trim().matches("^[0-9A-Fa-f]{4}$")
&& model.getString().trim().matches("^[0-9A-Fa-f]{4}$")) {
Device dev = DB.findDevice(manufacturer.getString().toLowerCase(),
model.getString().toLowerCase());
if (dev != null && !Strings.isNullOrEmpty(dev.getName())) {
model = new DERUTF8String(dev.getName());
}
}
return model;
}
}

View File

@ -0,0 +1 @@
package hirs.attestationca.portal.page.utils;

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%C.%M] %-5p : %m%n"/>
</Console>
<RollingFile name="FILE" fileName="./logs/HIRS_AttestationCA_Portal.log"
filePattern="./logs/HIRS_AttestationCA_Portal.log-%d{yyyy-MM-dd}-%i.log" >
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%C.%M] %-5p : %m%n</pattern>
</PatternLayout>
<Policies>
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy
size="10 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level = "WARN">
<AppenderRef ref="STDOUT" level="WARN" />
<AppenderRef ref="FILE"/>
</Root>
<SpringProfile name="!development, !production">
<Logger name="hirs.attestationca" level="trace" />
</SpringProfile>
<Logger name="org.hibernate" level="WARN" />
</Loggers>
<!-- prevents an out-of-memory exception caused by the debug logging of very large inserts -->
<category name="org.hibernate.event.def.AbstractFlushingEventListener">
<priority value="INFO"/>
</category>
</Configuration>