mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-18 20:47:58 +00:00
Merge remote-tracking branch 'origin/codebase-reset' into gradle-package
This commit is contained in:
commit
6763e4a87d
@ -0,0 +1,14 @@
|
||||
package hirs.attestationca.persist;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
||||
/**
|
||||
* Allows a user of the DBManager to modify the criteria object before processing.
|
||||
*/
|
||||
public interface CriteriaModifier<T> {
|
||||
/**
|
||||
* Allows a client to modify the criteria object by reference.
|
||||
* @param criteria The hibernate criteria builder object
|
||||
*/
|
||||
void modify(CriteriaQuery<T> criteria);
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package hirs.attestationca.persist;
|
||||
|
||||
/**
|
||||
* This class represents an <code>Exception</code> generated by a
|
||||
* <code>DBManageer</code>.
|
||||
*/
|
||||
public class DBManagerException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 3081536085161873284L;
|
||||
|
||||
/**
|
||||
* Creates a new <code>DBManagerException</code> that has the message
|
||||
* <code>msg</code>.
|
||||
*
|
||||
* @param msg
|
||||
* exception message
|
||||
*/
|
||||
public DBManagerException(final String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>DBManagerException</code> that wraps the given
|
||||
* <code>Throwable</code>.
|
||||
*
|
||||
* @param t
|
||||
* root cause
|
||||
*/
|
||||
public DBManagerException(final Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>DBManagerException</code> that has the message
|
||||
* <code>msg</code> and wraps the root cause.
|
||||
*
|
||||
* @param msg
|
||||
* exception message
|
||||
* @param t
|
||||
* root cause
|
||||
*/
|
||||
public DBManagerException(final String msg, final Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package hirs.attestationca.persist;
|
||||
|
||||
/**
|
||||
* This class represents an <code>Exception</code> generated by a
|
||||
* <code>DBManageer</code>.
|
||||
*/
|
||||
public class DBServiceException extends RuntimeException {
|
||||
private static final long serialVersionUID = 3081536085161873284L;
|
||||
|
||||
/**
|
||||
* Creates a new <code>DBManagerException</code> that has the message
|
||||
* <code>msg</code>.
|
||||
*
|
||||
* @param msg exception message
|
||||
*/
|
||||
public DBServiceException(final String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>DBManagerException</code> that wraps the given
|
||||
* <code>Throwable</code>.
|
||||
*
|
||||
* @param t root cause
|
||||
*/
|
||||
public DBServiceException(final Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>DBManagerException</code> that has the message
|
||||
* <code>msg</code> and wraps the root cause.
|
||||
*
|
||||
* @param msg exception message
|
||||
* @param t root cause
|
||||
*/
|
||||
DBServiceException(final String msg, final Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package hirs.attestationca.persist;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* FilteredRecordsList is an object designed to hold the results from multiple
|
||||
* queries necessary to populate the JQuery Datatables. The members include
|
||||
* the total number of records in the entity, the number of records returned
|
||||
* after filtering through the search bar, and the records themselves.
|
||||
*
|
||||
* @param <T> Class accepts generic for the list of data records.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
public class FilteredRecordsList<T> extends ArrayList<T> {
|
||||
|
||||
private long recordsTotal, recordsFiltered;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package hirs.attestationca.persist;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface defining methods for getting ordered lists from a data source. Includes
|
||||
* properties for sorting, paging, and searching.
|
||||
* @param <T> the record type, T.
|
||||
*/
|
||||
public interface OrderedListQuerier<T> {
|
||||
|
||||
/**
|
||||
* Returns a list of all <code>T</code>s that are ordered by a column and
|
||||
* direction (ASC, DESC) that is provided by the user. This method helps
|
||||
* support the server-side processing in the JQuery DataTables.
|
||||
*
|
||||
* @param clazz class type of <code>T</code>s to search for (may be null to
|
||||
* use Class<T>)
|
||||
* @param columnToOrder Column to be ordered
|
||||
* @param ascending direction of sort
|
||||
* @param firstResult starting point of first result in set
|
||||
* @param maxResults total number we want returned for display in table
|
||||
* @param search string of criteria to be matched to visible columns
|
||||
* @param searchableColumns Map of String and boolean values with column
|
||||
* headers and whether they should be searched. Boolean is true if field provides a
|
||||
* typical String that can be searched by Hibernate without transformation.
|
||||
* @return FilteredRecordsList object with query data
|
||||
* @throws DBManagerException if unable to create the list
|
||||
*/
|
||||
FilteredRecordsList getOrderedList(
|
||||
Class<? extends T> clazz, String columnToOrder,
|
||||
boolean ascending, int firstResult,
|
||||
int maxResults, String search,
|
||||
Map<String, Boolean> searchableColumns)
|
||||
throws DBManagerException;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of all <code>T</code>s that are ordered by a column and
|
||||
* direction (ASC, DESC) that is provided by the user. This method helps
|
||||
* support the server-side processing in the JQuery DataTables. For entities that support
|
||||
* soft-deletes, the returned list does not contain <code>T</code>s that have been soft-deleted.
|
||||
*
|
||||
* @param clazz class type of <code>T</code>s to search for (may be null to
|
||||
* use Class<T>)
|
||||
* @param columnToOrder Column to be ordered
|
||||
* @param ascending direction of sort
|
||||
* @param firstResult starting point of first result in set
|
||||
* @param maxResults total number we want returned for display in table
|
||||
* @param search string of criteria to be matched to visible columns
|
||||
* @param searchableColumns Map of String and boolean values with column
|
||||
* headers and whether they should be searched. Boolean is true if field provides a
|
||||
* typical String that can be searched by Hibernate without transformation.
|
||||
* @param criteriaModifier a way to modify the criteria used in the query
|
||||
* @return FilteredRecordsList object with query data
|
||||
* @throws DBManagerException if unable to create the list
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:parameternumber")
|
||||
FilteredRecordsList<T> getOrderedList(
|
||||
Class<? extends T> clazz, String columnToOrder,
|
||||
boolean ascending, int firstResult,
|
||||
int maxResults, String search,
|
||||
Map<String, Boolean> searchableColumns, CriteriaModifier<T> criteriaModifier)
|
||||
throws DBManagerException;
|
||||
}
|
@ -2,15 +2,15 @@ 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.EqualsAndHashCode;
|
||||
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 org.hibernate.annotations.UuidGenerator;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
@ -19,6 +19,7 @@ import java.util.UUID;
|
||||
/**
|
||||
* An abstract database entity.
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@MappedSuperclass
|
||||
public abstract class AbstractEntity implements Serializable {
|
||||
@ -31,8 +32,8 @@ public abstract class AbstractEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(generator = "uuid2", strategy=GenerationType.AUTO)
|
||||
@JdbcTypeCode(java.sql.Types.VARCHAR)
|
||||
@UuidGenerator(style = UuidGenerator.Style.AUTO)
|
||||
@GeneratedValue
|
||||
@Getter
|
||||
private UUID id;
|
||||
|
||||
@ -75,26 +76,4 @@ public abstract class AbstractEntity implements Serializable {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import jakarta.persistence.Column;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -23,6 +25,7 @@ public abstract class ArchivableEntity extends AbstractEntity {
|
||||
@Column(name = "archived_time")
|
||||
private Date archivedTime;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.LONGVARCHAR)
|
||||
@Column(name = "archived_description")
|
||||
private String archivedDescription;
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
package hirs.attestationca.persist.entity.manager;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface ReferenceDigestValueRepository extends JpaRepository<ReferenceDigestValue, UUID> {
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package hirs.attestationca.persist.entity.manager;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface SupplyChainValidationRepository extends JpaRepository<SupplyChainValidation, UUID> {
|
||||
}
|
@ -9,8 +9,7 @@ import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Transient;
|
||||
import lombok.Getter;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.bouncycastle.asn1.ASN1BitString;
|
||||
import org.bouncycastle.asn1.ASN1Encodable;
|
||||
import org.bouncycastle.asn1.ASN1GeneralizedTime;
|
||||
@ -76,11 +75,10 @@ import java.util.Objects;
|
||||
* It stores certain attributes separately from the serialized certificate to enable querying on
|
||||
* those attributes.
|
||||
*/
|
||||
@Log4j2
|
||||
@Entity
|
||||
public abstract class Certificate extends ArchivableEntity {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(Certificate.class);
|
||||
|
||||
/**
|
||||
* Holds the different certificate types.
|
||||
*/
|
||||
@ -561,8 +559,8 @@ public abstract class Certificate extends ArchivableEntity {
|
||||
try {
|
||||
return getX509Certificate().getVersion() - 1;
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("X509 Credential Version not found.");
|
||||
LOGGER.error(ex);
|
||||
log.warn("X509 Credential Version not found.");
|
||||
log.error(ex);
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@ -589,7 +587,7 @@ public abstract class Certificate extends ArchivableEntity {
|
||||
isIssuer = "";
|
||||
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException
|
||||
| NoSuchProviderException | SignatureException e) {
|
||||
LOGGER.error(e);
|
||||
log.error(e);
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_CERTIFICATE:
|
||||
@ -604,7 +602,7 @@ public abstract class Certificate extends ArchivableEntity {
|
||||
} catch (NoSuchAlgorithmException
|
||||
| InvalidKeyException
|
||||
| SignatureException sigEx) {
|
||||
LOGGER.error(sigEx);
|
||||
log.error(sigEx);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -769,7 +767,7 @@ public abstract class Certificate extends ArchivableEntity {
|
||||
asn1InputStream = new ASN1InputStream(oct.getOctets());
|
||||
asn1Primitive = asn1InputStream.readObject();
|
||||
} catch (IOException ioEx) {
|
||||
LOGGER.error(ioEx);
|
||||
log.error(ioEx);
|
||||
} finally {
|
||||
if (asn1InputStream != null) {
|
||||
asn1InputStream.close();
|
||||
@ -794,7 +792,7 @@ public abstract class Certificate extends ArchivableEntity {
|
||||
.getInstance(JcaX509ExtensionUtils.parseExtensionValue(authInfoAccess))));
|
||||
}
|
||||
} catch (IOException ioEx) {
|
||||
LOGGER.error(ioEx);
|
||||
log.error(ioEx);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
@ -993,7 +991,7 @@ public abstract class Certificate extends ArchivableEntity {
|
||||
certificateHolder.getSubjectPublicKeyInfo().parsePublicKey().toASN1Primitive()
|
||||
);
|
||||
} catch (IOException e) {
|
||||
LOGGER.info("No RSA Key Detected in certificate");
|
||||
log.info("No RSA Key Detected in certificate");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,72 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -92,7 +92,6 @@ public class ReferenceManifest extends ArchivableEntity {
|
||||
private String platformModel = null;
|
||||
@Column(nullable = false)
|
||||
private String fileName = null;
|
||||
// @Type(type="uuid-char")
|
||||
@JdbcTypeCode(java.sql.Types.VARCHAR)
|
||||
@Column
|
||||
private UUID associatedRim;
|
||||
|
@ -0,0 +1,124 @@
|
||||
package hirs.attestationca.persist.entity.userdefined;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import hirs.attestationca.persist.entity.ArchivableEntity;
|
||||
import hirs.attestationca.persist.enums.AppraisalStatus;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Stores results of a single element of the supply chain validation process.
|
||||
*/
|
||||
@Entity
|
||||
public class SupplyChainValidation extends ArchivableEntity {
|
||||
/**
|
||||
* Used to indicate which type of validation a result is related to.
|
||||
*/
|
||||
public enum ValidationType {
|
||||
/**
|
||||
* Validation of an endorsement credential.
|
||||
*/
|
||||
ENDORSEMENT_CREDENTIAL,
|
||||
|
||||
/**
|
||||
* Validation of a platform credential and also delta platform credentials from spec 1.1.
|
||||
*/
|
||||
PLATFORM_CREDENTIAL,
|
||||
|
||||
/**
|
||||
* Validation of a platform credential's attributes.
|
||||
*/
|
||||
PLATFORM_CREDENTIAL_ATTRIBUTES,
|
||||
|
||||
/**
|
||||
* Validation of the device firmware.
|
||||
*/
|
||||
FIRMWARE
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Column
|
||||
private final ValidationType validationType;
|
||||
|
||||
@Getter
|
||||
@Column
|
||||
private final AppraisalStatus.Status validationResult;
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "CertificatesUsedToValidate",
|
||||
joinColumns = { @JoinColumn(name = "validation_id", nullable = false) })
|
||||
private final List<Certificate> certificatesUsed;
|
||||
|
||||
@Getter
|
||||
@Column(length = MAX_MESSAGE_LENGTH)
|
||||
private final String message;
|
||||
|
||||
@Getter
|
||||
@Column
|
||||
private String rimId;
|
||||
|
||||
/**
|
||||
* Default constructor necessary for Hibernate.
|
||||
*/
|
||||
public SupplyChainValidation() {
|
||||
this.validationType = null;
|
||||
this.validationResult = AppraisalStatus.Status.ERROR;
|
||||
this.certificatesUsed = Collections.emptyList();
|
||||
this.message = null;
|
||||
this.rimId = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new SupplyChainValidation instance.
|
||||
*
|
||||
* @param validationType the type of validation this instance will represent; not null
|
||||
* @param validationResult whether the validation was successful or not
|
||||
* @param certificatesUsed certificates used, if any, in the validation process; not null
|
||||
* @param message a related information or error message; may be null
|
||||
*/
|
||||
public SupplyChainValidation(final ValidationType validationType,
|
||||
final AppraisalStatus.Status validationResult,
|
||||
final List<ArchivableEntity> certificatesUsed,
|
||||
final String message) {
|
||||
Preconditions.checkArgument(
|
||||
validationType != null,
|
||||
"Cannot construct a SupplyChainValidation with a null ValidationType"
|
||||
);
|
||||
|
||||
Preconditions.checkArgument(
|
||||
certificatesUsed != null,
|
||||
"Cannot construct a SupplyChainValidation with a null certificatesUsed"
|
||||
);
|
||||
|
||||
this.validationType = validationType;
|
||||
this.validationResult = validationResult;
|
||||
this.certificatesUsed = new ArrayList<>();
|
||||
this.rimId = "";
|
||||
for (ArchivableEntity ae : certificatesUsed) {
|
||||
if (ae instanceof ReferenceManifest) {
|
||||
this.rimId = ae.getId().toString();
|
||||
break;
|
||||
} else {
|
||||
this.certificatesUsed.add((Certificate) ae);
|
||||
}
|
||||
}
|
||||
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return certificates used in the process of performing the validation; may be empty
|
||||
*/
|
||||
public List<Certificate> getCertificatesUsed() {
|
||||
return Collections.unmodifiableList(certificatesUsed);
|
||||
}
|
||||
}
|
@ -0,0 +1,267 @@
|
||||
package hirs.attestationca.persist.entity.userdefined;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import hirs.attestationca.persist.entity.ArchivableEntity;
|
||||
import hirs.attestationca.persist.enums.AppraisalStatus;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A container class to group multiple related {@link SupplyChainValidation} instances
|
||||
* together.
|
||||
*/
|
||||
@Entity
|
||||
public class SupplyChainValidationSummary extends ArchivableEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "device_id")
|
||||
private final Device device;
|
||||
|
||||
private static final String DEVICE_ID_FIELD = "device.id";
|
||||
|
||||
@Column
|
||||
@Enumerated(EnumType.STRING)
|
||||
private final AppraisalStatus.Status overallValidationResult;
|
||||
|
||||
@Column(length = RESULT_MESSAGE_LENGTH)
|
||||
private final String message;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
|
||||
targetEntity = SupplyChainValidation.class, orphanRemoval = true)
|
||||
private final Set<SupplyChainValidation> validations;
|
||||
|
||||
/**
|
||||
* Default constructor necessary for Hibernate.
|
||||
*/
|
||||
protected SupplyChainValidationSummary() {
|
||||
this.device = null;
|
||||
overallValidationResult = AppraisalStatus.Status.FAIL;
|
||||
validations = Collections.emptySet();
|
||||
this.message = Strings.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class enables the retrieval of SupplyChainValidationSummaries by their attributes.
|
||||
*/
|
||||
public static class Selector {
|
||||
private final CrudRepository<SupplyChainValidationSummary, UUID>
|
||||
supplyChainValidationSummaryCrudManager;
|
||||
|
||||
private final Map<String, Object> fieldValueSelections;
|
||||
|
||||
/**
|
||||
* Construct a new Selector that will use the given {@link CrudRepository} to
|
||||
* retrieve SupplyChainValidationSummaries.
|
||||
*
|
||||
* @param supplyChainValidationSummaryCrudManager the summary manager to be used to retrieve
|
||||
* supply chain validation summaries
|
||||
*/
|
||||
public Selector(
|
||||
final CrudRepository<SupplyChainValidationSummary, UUID>
|
||||
supplyChainValidationSummaryCrudManager) {
|
||||
Preconditions.checkArgument(
|
||||
supplyChainValidationSummaryCrudManager != null,
|
||||
"supply chain validation summary manager cannot be null"
|
||||
);
|
||||
|
||||
this.supplyChainValidationSummaryCrudManager = supplyChainValidationSummaryCrudManager;
|
||||
this.fieldValueSelections = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the criterion that can be used to query for supply chain validation summaries
|
||||
* matching the configuration of this Selector.
|
||||
*
|
||||
* @return a Criterion that can be used to query for supply chain validation summaries
|
||||
* matching the configuration of this instance
|
||||
*/
|
||||
public Predicate[] getCriterion(final CriteriaBuilder criteriaBuilder) {
|
||||
Predicate[] predicates = new Predicate[fieldValueSelections.size()];
|
||||
CriteriaQuery<SupplyChainValidationSummary> query = criteriaBuilder.createQuery(SupplyChainValidationSummary.class);
|
||||
Root<SupplyChainValidationSummary> root = query.from(SupplyChainValidationSummary.class);
|
||||
|
||||
int i = 0;
|
||||
for (Map.Entry<String, Object> fieldValueEntry : fieldValueSelections.entrySet()) {
|
||||
predicates[i++] = criteriaBuilder.equal(root.get(fieldValueEntry.getKey()), fieldValueEntry.getValue());
|
||||
}
|
||||
|
||||
return predicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a field name and value to match.
|
||||
*
|
||||
* @param name the field name to query
|
||||
* @param value the value to query
|
||||
*/
|
||||
protected void setFieldValue(final String name, final Object value) {
|
||||
Object valueToAssign = value;
|
||||
|
||||
Preconditions.checkArgument(
|
||||
value != null,
|
||||
"field value cannot be null."
|
||||
);
|
||||
|
||||
if (value instanceof String) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty((String) value),
|
||||
"field value cannot be empty."
|
||||
);
|
||||
}
|
||||
|
||||
if (value instanceof byte[]) {
|
||||
byte[] valueBytes = (byte[]) value;
|
||||
|
||||
Preconditions.checkArgument(
|
||||
ArrayUtils.isNotEmpty(valueBytes),
|
||||
"field value cannot be empty."
|
||||
);
|
||||
|
||||
valueToAssign = Arrays.copyOf(valueBytes, valueBytes.length);
|
||||
}
|
||||
|
||||
fieldValueSelections.put(name, valueToAssign);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify a device id that supply chain validation summaries 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 SupplyChainValidationSummary.
|
||||
*
|
||||
* @param certMan the CrudManager to be used to retrieve persisted supply chain validation
|
||||
* summaries
|
||||
* @return a SupplyChainValidationSummary.Selector instance to use for retrieving certificates
|
||||
*/
|
||||
public static SupplyChainValidationSummary.Selector select(
|
||||
final CrudRepository<SupplyChainValidationSummary, UUID> certMan) {
|
||||
return new SupplyChainValidationSummary.Selector(certMan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new SupplyChainValidationSummary.
|
||||
*
|
||||
* @param device device that underwent supply chain validation
|
||||
* @param validations a Collection of Validations that should comprise this summary; not null
|
||||
*/
|
||||
public SupplyChainValidationSummary(final Device device,
|
||||
final Collection<SupplyChainValidation> validations) {
|
||||
|
||||
Preconditions.checkArgument(
|
||||
device != null,
|
||||
"Cannot construct a SupplyChainValidationSummary with a null device"
|
||||
);
|
||||
|
||||
Preconditions.checkArgument(
|
||||
validations != null,
|
||||
"Cannot construct a SupplyChainValidationSummary with a null validations list"
|
||||
);
|
||||
|
||||
this.device = device;
|
||||
AppraisalStatus status = calculateValidationResult(validations);
|
||||
this.overallValidationResult = status.getAppStatus();
|
||||
this.validations = new HashSet<>(validations);
|
||||
this.message = status.getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* This retrieves the device associated with the supply chain validation summaries.
|
||||
*
|
||||
* @return the validated device
|
||||
*/
|
||||
public Device getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the overall appraisal result
|
||||
*/
|
||||
public AppraisalStatus.Status getOverallValidationResult() {
|
||||
return overallValidationResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fail message if there is a failure.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the validations that this summary contains
|
||||
*/
|
||||
public Set<SupplyChainValidation> getValidations() {
|
||||
return Collections.unmodifiableSet(validations);
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method that helps determine the overall appraisal result.
|
||||
*
|
||||
* @param validations the validations to evaluate
|
||||
* @return the overall appraisal result
|
||||
*/
|
||||
private AppraisalStatus calculateValidationResult(
|
||||
final Collection<SupplyChainValidation> validations) {
|
||||
boolean hasAnyFailures = false;
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
for (SupplyChainValidation validation : validations) {
|
||||
switch (validation.getValidationResult()) {
|
||||
// if any error, then process overall as error immediately.
|
||||
case ERROR:
|
||||
return new AppraisalStatus(AppraisalStatus.Status.ERROR,
|
||||
validation.getMessage());
|
||||
case FAIL:
|
||||
hasAnyFailures = true;
|
||||
failureMsg.append(String.format("%s%n", validation.getValidationType()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if failures, but no error, indicate failure result.
|
||||
if (hasAnyFailures) {
|
||||
return new AppraisalStatus(AppraisalStatus.Status.FAIL,
|
||||
failureMsg.toString());
|
||||
}
|
||||
return new AppraisalStatus(AppraisalStatus.Status.PASS,
|
||||
Strings.EMPTY);
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package hirs.attestationca.persist.entity.userdefined.certificate;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.service.CertificateService;
|
||||
import hirs.attestationca.persist.service.selector.CertificateSelector;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import lombok.Getter;
|
||||
@ -44,6 +46,43 @@ public class CertificateAuthorityCredential extends Certificate {
|
||||
@Column
|
||||
private final String credentialType = "TCPA Trusted Platform Module Endorsement";
|
||||
|
||||
/**
|
||||
* This class enables the retrieval of CertificateAuthorityCredentials by their attributes.
|
||||
*/
|
||||
public static class Selector extends CertificateSelector<CertificateAuthorityCredential> {
|
||||
/**
|
||||
* Construct a new CertificateSelector that will use the given {@link CertificateService} to
|
||||
* retrieve one or many CertificateAuthorityCredentials.
|
||||
*
|
||||
* @param certificateManager the certificate manager to be used to retrieve certificates
|
||||
*/
|
||||
public Selector(final CertificateService certificateManager) {
|
||||
super(certificateManager, CertificateAuthorityCredential.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a subject key identifier that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param subjectKeyIdentifier a subject key identifier buffer to query, not empty or null
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public Selector bySubjectKeyIdentifier(final byte[] subjectKeyIdentifier) {
|
||||
setFieldValue(SUBJECT_KEY_IDENTIFIER_FIELD, subjectKeyIdentifier);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Selector for use in retrieving CertificateAuthorityCredentials.
|
||||
*
|
||||
* @param certMan the CertificateService to be used to retrieve persisted certificates
|
||||
* @return a CertificateAuthorityCredential.Selector instance to use for retrieving certificates
|
||||
*/
|
||||
public static Selector select(final CertificateService certMan) {
|
||||
return new Selector(certMan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new CertificateAuthorityCredential given its binary contents. The given
|
||||
* certificate should represent either an X509 certificate or X509 attribute certificate.
|
||||
|
@ -0,0 +1,41 @@
|
||||
package hirs.attestationca.persist.entity.userdefined.certificate;
|
||||
|
||||
import hirs.attestationca.persist.entity.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Getter
|
||||
@Entity
|
||||
public class ComponentResult extends AbstractEntity {
|
||||
|
||||
private UUID certificateId;
|
||||
private int componentHash;
|
||||
private String expected;
|
||||
private String actual;
|
||||
private boolean mismatched;
|
||||
|
||||
/**
|
||||
* Hibernate default constructor
|
||||
*/
|
||||
protected ComponentResult() {
|
||||
}
|
||||
|
||||
public ComponentResult(final UUID certificateId, final int componentHash,
|
||||
final String expected, final String actual) {
|
||||
this.certificateId = certificateId;
|
||||
this.componentHash = componentHash;
|
||||
this.expected = expected;
|
||||
this.actual = actual;
|
||||
this.mismatched = Objects.equals(expected, actual);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("ComponentResult[%d]: expected=[%s] actual=[%s]",
|
||||
componentHash, expected, actual);
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ import hirs.attestationca.persist.entity.userdefined.certificate.attributes.Plat
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TBBSecurityAssertion;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2;
|
||||
import hirs.attestationca.persist.service.CertificateService;
|
||||
import hirs.attestationca.persist.service.selector.CertificateSelector;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Transient;
|
||||
@ -46,6 +48,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class persists Platform credentials by extending the base Certificate
|
||||
@ -94,7 +97,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
||||
* TCG Platform Specification values
|
||||
* At this time these are placeholder values.
|
||||
*/
|
||||
private static final Map<String, String> TCG_PLATFORM_MAP = new HashMap<String, String>() {{
|
||||
private static final Map<String, String> TCG_PLATFORM_MAP = new HashMap<>() {{
|
||||
put("#00000000", "Unclassified");
|
||||
put("#00000001", "PC Client");
|
||||
put("#00000002", "PDA");
|
||||
@ -128,89 +131,89 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
||||
/**
|
||||
* 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;
|
||||
// }
|
||||
// }
|
||||
public static class Selector extends CertificateSelector<PlatformCredential> {
|
||||
/**
|
||||
* Construct a new CertificateSelector that will use the given {@link CertificateService} to
|
||||
* retrieve one or many PlatformCredentials.
|
||||
*
|
||||
* @param certificateManager the certificate manager to be used to retrieve certificates
|
||||
*/
|
||||
public Selector(final CertificateService 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;
|
||||
@ -275,9 +278,9 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
||||
* @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);
|
||||
// }
|
||||
public static Selector select(final CertificateService certMan) {
|
||||
return new Selector(certMan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new PlatformCredential given its binary contents. ParseFields is
|
||||
|
@ -52,6 +52,7 @@ public class ComponentClass {
|
||||
@Getter
|
||||
private String component, componentStr;
|
||||
private String registryType;
|
||||
@Getter
|
||||
private String componentIdentifier;
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,221 @@
|
||||
package hirs.attestationca.persist.entity.userdefined.info;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.DiscriminatorColumn;
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.annotations.DiscriminatorOptions;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* ComponentInfo is a class to hold Hardware component information
|
||||
* such as manufacturer, model, serial number and version.
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@DiscriminatorColumn(name = "componentTypeEnum", discriminatorType = DiscriminatorType.STRING)
|
||||
@DiscriminatorOptions(force = true)
|
||||
public class ComponentInfo implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "componentInfo_id")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@XmlElement
|
||||
@Column(nullable = false)
|
||||
private String componentManufacturer;
|
||||
|
||||
@XmlElement
|
||||
@Column(nullable = false)
|
||||
private String componentModel;
|
||||
|
||||
@XmlElement
|
||||
@Column
|
||||
private String componentSerial;
|
||||
|
||||
@XmlElement
|
||||
@Column
|
||||
private String componentRevision;
|
||||
|
||||
@XmlElement
|
||||
@Column
|
||||
private String componentClass;
|
||||
|
||||
/**
|
||||
* Get the Component's Manufacturer.
|
||||
* @return the Component's Manufacturer
|
||||
*/
|
||||
public String getComponentManufacturer() {
|
||||
return componentManufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Component's Model.
|
||||
* @return the Component's Model
|
||||
*/
|
||||
public String getComponentModel() {
|
||||
return componentModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Component's Serial Number.
|
||||
* @return the Component's Serial Number
|
||||
*/
|
||||
public String getComponentSerial() {
|
||||
return componentSerial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Component's Revision.
|
||||
* @return the Component's Revision
|
||||
*/
|
||||
public String getComponentRevision() {
|
||||
return componentRevision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Component's Class Registry.
|
||||
* @return the Component's Class
|
||||
*/
|
||||
public String getComponentClass() {
|
||||
return componentClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param componentManufacturer Component Manufacturer (must not be null)
|
||||
* @param componentModel Component Model (must not be null)
|
||||
* @param componentSerial Component Serial Number (can be null)
|
||||
* @param componentRevision Component Revision or Version (can be null)
|
||||
*/
|
||||
public ComponentInfo(final String componentManufacturer,
|
||||
final String componentModel,
|
||||
final String componentSerial,
|
||||
final String componentRevision) {
|
||||
Assert.state(isComplete(
|
||||
componentManufacturer,
|
||||
componentModel,
|
||||
componentSerial,
|
||||
componentRevision),
|
||||
"ComponentInfo: manufacturer and/or "
|
||||
+ "model can not be null");
|
||||
this.componentManufacturer = componentManufacturer.trim();
|
||||
this.componentModel = componentModel.trim();
|
||||
if (componentSerial != null) {
|
||||
this.componentSerial = componentSerial.trim();
|
||||
} else {
|
||||
this.componentSerial = StringUtils.EMPTY;
|
||||
}
|
||||
if (componentRevision != null) {
|
||||
this.componentRevision = componentRevision.trim();
|
||||
} else {
|
||||
this.componentRevision = StringUtils.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param componentManufacturer Component Manufacturer (must not be null)
|
||||
* @param componentModel Component Model (must not be null)
|
||||
* @param componentSerial Component Serial Number (can be null)
|
||||
* @param componentRevision Component Revision or Version (can be null)
|
||||
* @param componentClass Component Class (can be null)
|
||||
*/
|
||||
public ComponentInfo(final String componentManufacturer,
|
||||
final String componentModel,
|
||||
final String componentSerial,
|
||||
final String componentRevision,
|
||||
final String componentClass) {
|
||||
Assert.state(isComplete(
|
||||
componentManufacturer,
|
||||
componentModel,
|
||||
componentSerial,
|
||||
componentRevision),
|
||||
"ComponentInfo: manufacturer and/or "
|
||||
+ "model can not be null");
|
||||
this.componentManufacturer = componentManufacturer.trim();
|
||||
this.componentModel = componentModel.trim();
|
||||
if (componentSerial != null) {
|
||||
this.componentSerial = componentSerial.trim();
|
||||
} else {
|
||||
this.componentSerial = StringUtils.EMPTY;
|
||||
}
|
||||
if (componentRevision != null) {
|
||||
this.componentRevision = componentRevision.trim();
|
||||
} else {
|
||||
this.componentRevision = StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
if (componentClass != null) {
|
||||
this.componentClass = componentClass;
|
||||
} else {
|
||||
this.componentClass = StringUtils.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given properties represent a
|
||||
* ComponentInfo that will be useful in validation.
|
||||
* Currently, only components which have a non-null
|
||||
* manufacturer and model are considered valid.
|
||||
*
|
||||
* @param componentManufacturer a String containing a component's manufacturer
|
||||
* @param componentModel a String representing a component's model
|
||||
* @param componentSerial a String representing a component's serial number
|
||||
* @param componentRevision a String representing a component's revision
|
||||
* @return true if the component is valid, false if not
|
||||
*/
|
||||
public static boolean isComplete(final String componentManufacturer,
|
||||
final String componentModel,
|
||||
final String componentSerial,
|
||||
final String componentRevision) {
|
||||
return !(StringUtils.isEmpty(componentManufacturer)
|
||||
|| StringUtils.isEmpty(componentModel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ComponentInfo that = (ComponentInfo) o;
|
||||
return Objects.equals(id, that.id)
|
||||
&& Objects.equals(componentManufacturer, that.componentManufacturer)
|
||||
&& Objects.equals(componentModel, that.componentModel)
|
||||
&& Objects.equals(componentSerial, that.componentSerial)
|
||||
&& Objects.equals(componentRevision, that.componentRevision)
|
||||
&& Objects.equals(componentClass, that.componentClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, componentManufacturer, componentModel,
|
||||
componentSerial, componentRevision, componentClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("ComponentInfo{"
|
||||
+ "componentManufacturer='%s'"
|
||||
+ ", componentModel='%s'"
|
||||
+ ", componentSerial='%s'"
|
||||
+ ", componentRevision='%s'"
|
||||
+ ", componentClass='%s'}",
|
||||
componentManufacturer,
|
||||
componentModel, componentSerial,
|
||||
componentRevision, componentClass);
|
||||
}
|
||||
}
|
@ -2,7 +2,9 @@ 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.ReferenceManifestService;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
|
||||
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
|
||||
import hirs.utils.SwidResource;
|
||||
import hirs.utils.xjc.BaseElement;
|
||||
import hirs.utils.xjc.Directory;
|
||||
@ -93,6 +95,105 @@ public class BaseReferenceManifest extends ReferenceManifest {
|
||||
private String linkHref = null;
|
||||
private String linkRel = null;
|
||||
|
||||
/**
|
||||
* This class enables the retrieval of BaseReferenceManifest by their attributes.
|
||||
*/
|
||||
public static class Selector extends ReferenceManifestSelector<BaseReferenceManifest> {
|
||||
/**
|
||||
* Construct a new ReferenceManifestSelector that will use
|
||||
* the given (@link ReferenceManifestService}
|
||||
* to retrieve one or may BaseReferenceManifest.
|
||||
*
|
||||
* @param referenceManifestManager the reference manifest manager to be used to retrieve
|
||||
* reference manifests.
|
||||
*/
|
||||
public Selector(final ReferenceManifestService referenceManifestManager) {
|
||||
super(referenceManifestManager, BaseReferenceManifest.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform manufacturer that rims must have to be considered
|
||||
* as matching.
|
||||
* @param manufacturer string for the manufacturer
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byManufacturer(final String manufacturer) {
|
||||
setFieldValue(PLATFORM_MANUFACTURER, manufacturer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform model that rims must have to be considered
|
||||
* as matching.
|
||||
* @param model string for the model
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byModel(final String model) {
|
||||
setFieldValue(PLATFORM_MODEL, model);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform manufacturer/model that rims must have to be considered
|
||||
* as matching.
|
||||
* @param manufacturer string for the manufacturer
|
||||
* @param model string for the model
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byManufacturerModel(final String manufacturer, final String model) {
|
||||
setFieldValue(PLATFORM_MANUFACTURER, manufacturer);
|
||||
setFieldValue(PLATFORM_MODEL, model);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform manufacturer/model/base flag that rims must have to be considered
|
||||
* as matching.
|
||||
* @param manufacturer string for the manufacturer
|
||||
* @param model string for the model
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byManufacturerModelBase(final String manufacturer, final String model) {
|
||||
setFieldValue(PLATFORM_MANUFACTURER, manufacturer);
|
||||
setFieldValue(PLATFORM_MODEL, model);
|
||||
setFieldValue("swidPatch", false);
|
||||
setFieldValue("swidSupplemental", false);
|
||||
//setFieldValue("", false); //corpus?
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the device name that rims must have to be considered
|
||||
* as matching.
|
||||
* @param deviceName string for the deviceName
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byDeviceName(final String deviceName) {
|
||||
setFieldValue("deviceName", deviceName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the RIM hash associated with the base RIM.
|
||||
* @param base64Hash the hash of the file associated with the rim
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byBase64Hash(final String base64Hash) {
|
||||
setFieldValue(BASE_64_HASH_FIELD, base64Hash);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the RIM hash associated with the base RIM.
|
||||
* @param hexDecHash the hash of the file associated with the rim
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byHexDecHash(final String hexDecHash) {
|
||||
setFieldValue(HEX_DEC_HASH_FIELD, hexDecHash);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Support constructor for the RIM object.
|
||||
*
|
||||
@ -242,6 +343,17 @@ public class BaseReferenceManifest extends ReferenceManifest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Selector for use in retrieving ReferenceManifest.
|
||||
*
|
||||
* @param rimMan the ReferenceManifestService to be used to retrieve
|
||||
* persisted RIMs
|
||||
* @return a Selector instance to use for retrieving RIMs
|
||||
*/
|
||||
public static Selector select(final ReferenceManifestService rimMan) {
|
||||
return new Selector(rimMan);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -3,20 +3,33 @@ 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 hirs.attestationca.persist.service.ReferenceManifestService;
|
||||
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
|
||||
import hirs.utils.tpm.eventlog.TCGEventLog;
|
||||
import hirs.utils.tpm.eventlog.TpmPcrEvent;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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.
|
||||
* Similar to {@link SupportReferenceManifest}
|
||||
* however this is the live log from the client.
|
||||
*/
|
||||
@Log4j2
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Entity
|
||||
public class EventLogMeasurements extends ReferenceManifest {
|
||||
|
||||
@ -28,6 +41,66 @@ public class EventLogMeasurements extends ReferenceManifest {
|
||||
@Getter @Setter
|
||||
private AppraisalStatus.Status overallValidationResult = AppraisalStatus.Status.FAIL;
|
||||
|
||||
/**
|
||||
* This class enables the retrieval of SupportReferenceManifest by their attributes.
|
||||
*/
|
||||
public static class Selector extends ReferenceManifestSelector<EventLogMeasurements> {
|
||||
/**
|
||||
* Construct a new ReferenceManifestSelector that
|
||||
* will use the given (@link ReferenceManifestService}
|
||||
* to retrieve one or may SupportReferenceManifest.
|
||||
*
|
||||
* @param referenceManifestManager the reference manifest manager to be used to retrieve
|
||||
* reference manifests.
|
||||
*/
|
||||
public Selector(final ReferenceManifestService referenceManifestManager) {
|
||||
super(referenceManifestManager, EventLogMeasurements.class, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform manufacturer that rims must have to be considered
|
||||
* as matching.
|
||||
* @param manufacturer string for the manufacturer
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byManufacturer(final String manufacturer) {
|
||||
setFieldValue(PLATFORM_MANUFACTURER, manufacturer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform model that rims must have to be considered
|
||||
* as matching.
|
||||
* @param model string for the model
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byModel(final String model) {
|
||||
setFieldValue(PLATFORM_MODEL, model);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the device name that rims must have to be considered
|
||||
* as matching.
|
||||
* @param deviceName string for the deviceName
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byDeviceName(final String deviceName) {
|
||||
setFieldValue("deviceName", deviceName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the RIM hash associated with the Event Log.
|
||||
* @param hexDecHash the hash of the file associated with the rim
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byHexDecHash(final String hexDecHash) {
|
||||
setFieldValue(HEX_DEC_HASH_FIELD, hexDecHash);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Support constructor for the RIM object.
|
||||
*
|
||||
@ -61,4 +134,57 @@ public class EventLogMeasurements extends ReferenceManifest {
|
||||
super();
|
||||
this.pcrHash = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Selector for use in retrieving ReferenceManifest.
|
||||
*
|
||||
* @param rimMan the ReferenceManifestService to be used to retrieve
|
||||
* persisted RIMs
|
||||
* @return a Selector instance to use for retrieving RIMs
|
||||
*/
|
||||
public static Selector select(final ReferenceManifestService rimMan) {
|
||||
return new Selector(rimMan);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<>();
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package hirs.attestationca.persist.entity.userdefined.rim;
|
||||
|
||||
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.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
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
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
@Table(name = "ReferenceDigestValue")
|
||||
@Access(AccessType.FIELD)
|
||||
public class ReferenceDigestValue extends ArchivableEntity {
|
||||
|
||||
@JdbcTypeCode(java.sql.Types.VARCHAR)
|
||||
@Column
|
||||
private UUID baseRimId;
|
||||
@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;
|
||||
@Column(nullable = false)
|
||||
private boolean updated;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Constructor with parameters for all associated data.
|
||||
* @param baseRimId the UUID of the associated record
|
||||
* @param supportRimId the UUID of the associated record
|
||||
* @param manufacturer associated creator for this information
|
||||
* @param model the specific device type
|
||||
* @param pcrIndex the event number
|
||||
* @param digestValue the key digest value
|
||||
* @param eventType the event type to store
|
||||
* @param matchFail the status of the baseline check
|
||||
* @param patched the status of the value being updated to patch
|
||||
* @param updated the status of the value being updated with info
|
||||
* @param contentBlob the data value of the content
|
||||
*/
|
||||
public ReferenceDigestValue(final UUID baseRimId, final UUID supportRimId,
|
||||
final String manufacturer, final String model,
|
||||
final int pcrIndex, final String digestValue,
|
||||
final String eventType, final boolean matchFail,
|
||||
final boolean patched, final boolean updated,
|
||||
final byte[] contentBlob) {
|
||||
this.baseRimId = baseRimId;
|
||||
this.supportRimId = supportRimId;
|
||||
this.manufacturer = manufacturer;
|
||||
this.model = model;
|
||||
this.pcrIndex = pcrIndex;
|
||||
this.digestValue = digestValue;
|
||||
this.eventType = eventType;
|
||||
this.matchFail = matchFail;
|
||||
this.patched = patched;
|
||||
this.updated = updated;
|
||||
this.contentBlob = Arrays.clone(contentBlob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to update the attributes of this object.
|
||||
* @param support the associated RIM.
|
||||
* @param baseRimId the main id to update
|
||||
*/
|
||||
public void updateInfo(final SupportReferenceManifest support, final UUID baseRimId) {
|
||||
if (support != null) {
|
||||
setBaseRimId(baseRimId);
|
||||
setManufacturer(support.getPlatformManufacturer());
|
||||
setModel(support.getPlatformModel());
|
||||
setUpdated(true);
|
||||
if (support.isSwidPatch()) {
|
||||
// come back to this later, how does this get
|
||||
// identified to be patched
|
||||
setPatched(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string of the classes fields.
|
||||
* @return a string
|
||||
*/
|
||||
public String toString() {
|
||||
return String.format("ReferenceDigestValue: {%s, %d, %s, %s, "
|
||||
+ "matchFail - %b, updated - %b, patched - %b}",
|
||||
model, pcrIndex, digestValue, eventType, matchFail, updated, patched);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ 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.ReferenceManifestService;
|
||||
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
|
||||
import hirs.utils.tpm.eventlog.TCGEventLog;
|
||||
import hirs.utils.tpm.eventlog.TpmPcrEvent;
|
||||
import jakarta.persistence.Column;
|
||||
@ -34,6 +36,78 @@ public class SupportReferenceManifest extends ReferenceManifest {
|
||||
@Column
|
||||
private boolean processed = false;
|
||||
|
||||
/**
|
||||
* This class enables the retrieval of SupportReferenceManifest by their attributes.
|
||||
*/
|
||||
public static class Selector extends ReferenceManifestSelector<SupportReferenceManifest> {
|
||||
/**
|
||||
* Construct a new ReferenceManifestSelector that will
|
||||
* use the given (@link ReferenceManifestService}
|
||||
* to retrieve one or may SupportReferenceManifest.
|
||||
*
|
||||
* @param referenceManifestManager the reference manifest manager to be used to retrieve
|
||||
* reference manifests.
|
||||
*/
|
||||
public Selector(final ReferenceManifestService referenceManifestManager) {
|
||||
super(referenceManifestManager, SupportReferenceManifest.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform manufacturer that rims must have to be considered
|
||||
* as matching.
|
||||
* @param manufacturer string for the manufacturer
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byManufacturer(final String manufacturer) {
|
||||
setFieldValue(PLATFORM_MANUFACTURER, manufacturer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the platform model that rims must have to be considered
|
||||
* as matching.
|
||||
* @param manufacturer string for the manufacturer
|
||||
* @param model string for the model
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byManufacturerModel(final String manufacturer, final String model) {
|
||||
setFieldValue(PLATFORM_MANUFACTURER, manufacturer);
|
||||
setFieldValue(PLATFORM_MODEL, model);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the device name that rims must have to be considered
|
||||
* as matching.
|
||||
* @param deviceName string for the deviceName
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byDeviceName(final String deviceName) {
|
||||
setFieldValue("deviceName", deviceName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the file name that rims should have.
|
||||
* @param fileName the name of the file associated with the rim
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byFileName(final String fileName) {
|
||||
setFieldValue(RIM_FILENAME_FIELD, fileName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the RIM hash associated with the support RIM.
|
||||
* @param hexDecHash the hash of the file associated with the rim
|
||||
* @return this instance
|
||||
*/
|
||||
public Selector byHexDecHash(final String hexDecHash) {
|
||||
setFieldValue(HEX_DEC_HASH_FIELD, hexDecHash);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main constructor for the RIM object. This takes in a byte array of a
|
||||
* valid swidtag file and parses the information.
|
||||
@ -69,6 +143,16 @@ public class SupportReferenceManifest extends ReferenceManifest {
|
||||
this.pcrHash = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Selector for use in retrieving ReferenceManifest.
|
||||
*
|
||||
* @param rimMan the ReferenceManifestService to be used to retrieve
|
||||
* persisted RIMs
|
||||
* @return a Selector instance to use for retrieving RIMs
|
||||
*/
|
||||
public static Selector select(final ReferenceManifestService rimMan) {
|
||||
return new Selector(rimMan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter method for the expected PCR values contained within the support
|
||||
@ -111,4 +195,13 @@ public class SupportReferenceManifest extends ReferenceManifest {
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a method to indicate whether or not this support
|
||||
* rim is a base log file.
|
||||
* @return flag for base.
|
||||
*/
|
||||
public boolean isBaseSupport() {
|
||||
return !this.isSwidSupplemental() && !this.isSwidPatch();
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
package hirs.attestationca.persist.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Class to capture appraisal results and corresponding messages.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AppraisalStatus {
|
||||
/**
|
||||
* Enum used to represent appraisal status.
|
||||
@ -56,51 +61,4 @@ public class AppraisalStatus {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.service.selector.CertificateSelector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface CertificateService<T extends Certificate> {
|
||||
|
||||
Certificate saveCertificate(Certificate certificate);
|
||||
|
||||
<T extends Certificate> List<T> fetchCertificates(Class<T> classType);
|
||||
|
||||
Certificate updateCertificate(Certificate certificate, UUID certificateId);
|
||||
|
||||
Certificate updateCertificate(Certificate certificate);
|
||||
|
||||
void deleteCertificate(Certificate certificate);
|
||||
|
||||
<T extends Certificate> Set<T> get(CertificateSelector certificateSelector);
|
||||
}
|
@ -2,19 +2,84 @@ package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.entity.manager.CertificateRepository;
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.service.selector.CertificateSelector;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class CertificateServiceImpl {
|
||||
public class CertificateServiceImpl<T extends Certificate> extends DefaultDbService<Certificate> implements CertificateService<Certificate> {
|
||||
|
||||
@Autowired(required = false)
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private CertificateRepository repository;
|
||||
|
||||
private void saveCertificate(Certificate certificate) {
|
||||
repository.save(certificate);
|
||||
@Override
|
||||
public Certificate saveCertificate(Certificate certificate) {
|
||||
return repository.save(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Certificate> List<T> fetchCertificates(Class<T> classType) {
|
||||
return (List<T>) repository.findAll(Sort.sort(classType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate updateCertificate(Certificate certificate, UUID certificateId) {
|
||||
return saveCertificate(certificate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate updateCertificate(Certificate certificate) {
|
||||
return saveCertificate(certificate);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does not need to be used directly as it is used by {@link CertificateSelector}'s
|
||||
* get* methods. Regardless, it may be used to retrieve certificates by other code in this
|
||||
* package, given a configured CertificateSelector.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* CertificateSelector certSelector =
|
||||
* new CertificateSelector(Certificate.Type.CERTIFICATE_AUTHORITY)
|
||||
* .byIssuer("CN=Some certain issuer");
|
||||
*
|
||||
* Set<Certificate> certificates = certificateManager.get(certSelector);}
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the type of certificate that will be retrieved
|
||||
* @param certificateSelector a configured {@link CertificateSelector} to use for querying
|
||||
* @return the resulting set of Certificates, possibly empty
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Certificate> Set<T> get(final CertificateSelector certificateSelector) {
|
||||
// return new HashSet<>(
|
||||
// (List<T>) getWithCriteria(
|
||||
// certificateSelector.getCertificateClass(),
|
||||
// Collections.singleton(certificateSelector.getCriterion())
|
||||
// )
|
||||
// );
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a certificate from the database.
|
||||
*
|
||||
* @param certificate the certificate to delete
|
||||
* @return true if deletion was successful, false otherwise
|
||||
*/
|
||||
public void deleteCertificate(final Certificate certificate) {
|
||||
repository.delete(certificate);
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
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;
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.DBManagerException;
|
||||
import hirs.attestationca.persist.entity.ArchivableEntity;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.retry.RetryCallback;
|
||||
import org.springframework.retry.RetryContext;
|
||||
import org.springframework.retry.RetryListener;
|
||||
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Log4j2
|
||||
@Service
|
||||
@NoArgsConstructor
|
||||
public class DefaultDbService<T extends ArchivableEntity> extends HibernateDbService<T> {
|
||||
/**
|
||||
* 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;
|
||||
private static final int MAX_CLASS_CACHE_ENTRIES = 500;
|
||||
|
||||
private Class<T> clazz;
|
||||
@PersistenceContext
|
||||
private EntityManager entityManager;
|
||||
private JpaRepository repository;
|
||||
// structure for retrying methods in the database
|
||||
private RetryTemplate retryTemplate;
|
||||
|
||||
/**
|
||||
* Creates a new <code>DefaultDbService</code>.
|
||||
*
|
||||
* @param clazz Class to search for when doing Hibernate queries,
|
||||
* unfortunately class type of T cannot be determined using only T
|
||||
*/
|
||||
public DefaultDbService(final Class<T> clazz) {
|
||||
super(clazz, null);
|
||||
setRetryTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameters used to retry database transactions. The retry template will
|
||||
* retry transactions that throw a LockAcquisitionException or StaleObjectStateException.
|
||||
*/
|
||||
public final void setRetryTemplate() {
|
||||
Map<Class<? extends Throwable>, Boolean> exceptionsToRetry = new HashMap<>();
|
||||
exceptionsToRetry.put(LockAcquisitionException.class, true);
|
||||
exceptionsToRetry.put(StaleObjectStateException.class, true);
|
||||
|
||||
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(
|
||||
DEFAULT_MAX_RETRY_ATTEMPTS,
|
||||
exceptionsToRetry,
|
||||
true,
|
||||
false
|
||||
);
|
||||
|
||||
FixedBackOffPolicy backoffPolicy = new FixedBackOffPolicy();
|
||||
backoffPolicy.setBackOffPeriod(DEFAULT_RETRY_WAIT_TIME_MS);
|
||||
this.retryTemplate = new RetryTemplate();
|
||||
this.retryTemplate.setRetryPolicy(retryPolicy);
|
||||
this.retryTemplate.setBackOffPolicy(backoffPolicy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a retry listener to be notified of retry activity.
|
||||
* @param retryListener the retry listener
|
||||
*/
|
||||
public void addRetryListener(final RetryListener retryListener) {
|
||||
retryTemplate.registerListener(retryListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Object</code> from the database. This searches the
|
||||
* database for an entry whose name matches <code>name</code>. It then
|
||||
* reconstructs the <code>Object</code> from the database entry.
|
||||
*
|
||||
* @param name name of the object
|
||||
* @return object if found, otherwise null.
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
public final T get(final String name) throws DBManagerException {
|
||||
return retryTemplate.execute(new RetryCallback<T, DBManagerException>() {
|
||||
@Override
|
||||
public T doWithRetry(final RetryContext context) throws DBManagerException {
|
||||
return doGet(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Object</code> from the database. This searches the
|
||||
* database for an entry whose id matches <code>id</code>. It then
|
||||
* reconstructs the <code>Object</code> from the database entry.
|
||||
*
|
||||
* @param id id of the object
|
||||
* @return object if found, otherwise null.
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
public final T get(final Serializable id) throws DBManagerException {
|
||||
return retryTemplate.execute(new RetryCallback<T, DBManagerException>() {
|
||||
@Override
|
||||
public T doWithRetry(final RetryContext context) throws DBManagerException {
|
||||
return doGet(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Object</code> from the database. This searches the
|
||||
* database for an entry whose name matches <code>name</code>. It then
|
||||
* reconstructs the <code>Object</code> from the database entry.
|
||||
*
|
||||
* @param name name of the object
|
||||
* @return object if found, otherwise null.
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
protected T doGet(final String name) throws DBManagerException {
|
||||
log.debug("getting object: {}", name);
|
||||
if (name == null) {
|
||||
log.debug("null name argument");
|
||||
return null;
|
||||
}
|
||||
|
||||
Object entity = entityManager.find(clazz, name);
|
||||
entityManager.detach(entity);
|
||||
|
||||
return clazz.cast(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Object</code> from the database. This searches the
|
||||
* database for an entry whose id matches <code>id</code>. It then
|
||||
* reconstructs the <code>Object</code> from the database entry.
|
||||
*
|
||||
* @param id id of the object
|
||||
* @return object if found, otherwise null.
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
protected T doGet(final Serializable id) throws DBManagerException {
|
||||
log.debug("getting object: {}", id);
|
||||
if (id == null) {
|
||||
log.debug("null id argument");
|
||||
return null;
|
||||
}
|
||||
|
||||
Object entity = entityManager.find(clazz, id);
|
||||
entityManager.detach(entity);
|
||||
|
||||
return clazz.cast(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Archives the named object and updates it in the database.
|
||||
*
|
||||
* @param name name of the object to archive
|
||||
* @return true if the object was successfully found and archived, false if the object was not
|
||||
* found
|
||||
* @throws DBManagerException if the object is not an instance of <code>ArchivableEntity</code>
|
||||
*/
|
||||
// @Override
|
||||
// public final boolean archive(final String name) throws DBManagerException {
|
||||
// log.debug("archiving object: {}", name);
|
||||
// if (name == null) {
|
||||
// log.debug("null name argument");
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// T target = get(name);
|
||||
// if (target == null) {
|
||||
// return false;
|
||||
// }
|
||||
// if (!(target instanceof ArchivableEntity)) {
|
||||
// throw new DBManagerException("unable to archive non-archivable object");
|
||||
// }
|
||||
//
|
||||
// ((ArchivableEntity) target).archive();
|
||||
// repository.save(target);
|
||||
// return true;
|
||||
// }
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.DBManagerException;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract class that has the underlying Hibernate commands used by other DB Managers.
|
||||
* This class exists primarily to reduce code in {@link hirs.attestationca.persist.service.DefaultDbService} which retries these methods
|
||||
* using a RetryTemplate.
|
||||
*
|
||||
* @param <T> type of objects to manage by this manager
|
||||
*/
|
||||
@Log4j2
|
||||
public abstract class HibernateDbService<T> {
|
||||
|
||||
private static final int MAX_CLASS_CACHE_ENTRIES = 500;
|
||||
|
||||
private final Class<T> clazz;
|
||||
@PersistenceContext
|
||||
private EntityManager entityManager;
|
||||
private CriteriaBuilder criteriaBuilder;
|
||||
private CriteriaQuery<T> criteriaQuery;
|
||||
|
||||
/**
|
||||
* Creates a new <code>AbstractDbManager</code>.
|
||||
*
|
||||
* @param clazz Class to search for when doing Hibernate queries,
|
||||
* unfortunately class type of T cannot be determined using only T
|
||||
* @param entityManager the session factory to use to interact with the database
|
||||
*/
|
||||
public HibernateDbService(final Class<T> clazz, final EntityManager entityManager) {
|
||||
if (clazz == null) {
|
||||
log.error("HibernateDbService cannot be instantiated with a null class");
|
||||
throw new IllegalArgumentException(
|
||||
"HibernateDbService cannot be instantiated with a null class"
|
||||
);
|
||||
}
|
||||
// if (entityManager == null) {
|
||||
// log.error("HibernateDbService cannot be instantiated with a null SessionFactory");
|
||||
// throw new IllegalArgumentException(
|
||||
// "HibernateDbService cannot be instantiated with a null SessionFactory"
|
||||
// );
|
||||
// }
|
||||
this.clazz = clazz;
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
public HibernateDbService() {
|
||||
clazz = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all <code>T</code>s of type <code>clazz</code> in the database, with an
|
||||
* additional restriction also specified in the query.
|
||||
* <p>
|
||||
* This would be useful if <code>T</code> has several subclasses being
|
||||
* managed. This class argument allows the caller to limit which types of
|
||||
* <code>T</code> should be returned.
|
||||
*
|
||||
* @param clazz class type of <code>T</code>s to search for (may be null to
|
||||
* use Class<T>)
|
||||
* @param additionalRestriction - an added Criterion to use in the query, null for none
|
||||
* @return list of <code>T</code> names
|
||||
* @throws DBManagerException if unable to search the database
|
||||
*/
|
||||
protected List<T> doGetList(final Class<? extends T> clazz)
|
||||
throws DBManagerException {
|
||||
log.debug("Getting object list");
|
||||
Class<? extends T> searchClass = clazz;
|
||||
if (clazz == null) {
|
||||
log.debug("clazz is null");
|
||||
searchClass = this.clazz;
|
||||
}
|
||||
|
||||
List<T> objects = new ArrayList<>();
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the object from the database. This removes all of the database
|
||||
* entries that stored information with regards to the this object.
|
||||
* <p>
|
||||
* If the object is referenced by any other tables then this will throw a
|
||||
* <code>DBManagerException</code>.
|
||||
*
|
||||
* @param name name of the object to delete
|
||||
* @return true if successfully found and deleted the object
|
||||
* @throws DBManagerException if unable to find the baseline or delete it
|
||||
* from the database
|
||||
*/
|
||||
// protected boolean doDelete(final String name) throws DBManagerException {
|
||||
// log.debug("deleting object: {}", name);
|
||||
// if (name == null) {
|
||||
// log.debug("null name argument");
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// boolean deleted = false;
|
||||
// Session session = entityManager.unwrap(Session.class);
|
||||
// try {
|
||||
// log.debug("retrieving object from db");
|
||||
// criteriaBuilder = session.getCriteriaBuilder();
|
||||
// criteriaQuery = criteriaBuilder.createQuery(clazz);
|
||||
// Root<T> root = criteriaQuery.from(clazz);
|
||||
// criteriaQuery.select(root).where(criteriaBuilder.equal(root.get("name"), name));
|
||||
//
|
||||
// Object object = session.createQuery(criteriaQuery).getSingleResult();
|
||||
//
|
||||
// if (clazz.isInstance(object)) {
|
||||
// T objectOfTypeT = clazz.cast(object);
|
||||
// log.debug("found object, deleting it");
|
||||
// session.delete(objectOfTypeT);
|
||||
// deleted = true;
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// final String msg = "unable to retrieve object";
|
||||
// log.error(msg, e);
|
||||
// throw new DBManagerException(msg, e);
|
||||
// }
|
||||
// return deleted;
|
||||
// }
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ReferenceDigestValueService {
|
||||
|
||||
ReferenceDigestValue saveReferenceDigestValue(ReferenceDigestValue referenceDigestValue);
|
||||
|
||||
List<ReferenceDigestValue> fetchDigestValues();
|
||||
|
||||
ReferenceDigestValue updateRefDigestValue(ReferenceDigestValue referenceDigestValue, UUID rdvId);
|
||||
|
||||
List<ReferenceDigestValue> getValuesByRimId(ReferenceManifest baseRim);
|
||||
|
||||
void deleteRefDigestValueById(UUID rdvId);
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.datatables.mapping.DataTablesInput;
|
||||
import org.springframework.data.jpa.datatables.mapping.DataTablesOutput;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class ReferenceDigestValueServiceImpl extends DefaultDbService<ReferenceDigestValue> implements ReferenceDigestValueService {
|
||||
|
||||
@Autowired
|
||||
private ReferenceDigestValueRepository repository;
|
||||
|
||||
@Override
|
||||
public ReferenceDigestValue saveReferenceDigestValue(ReferenceDigestValue referenceDigestValue) {
|
||||
return repository.save(referenceDigestValue);
|
||||
}
|
||||
|
||||
public List<ReferenceDigestValue> findAll() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReferenceDigestValue> fetchDigestValues() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReferenceDigestValue updateRefDigestValue(ReferenceDigestValue referenceDigestValue, UUID rdvId) {
|
||||
return saveReferenceDigestValue(referenceDigestValue);
|
||||
}
|
||||
|
||||
public ReferenceDigestValue updateRefDigestValue(ReferenceDigestValue referenceDigestValue) {
|
||||
if (referenceDigestValue.getId() != null) {
|
||||
return updateRefDigestValue(referenceDigestValue, referenceDigestValue.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ReferenceDigestValue> getValuesByRimId(ReferenceManifest baseRim) {
|
||||
List<ReferenceDigestValue> results = new LinkedList<>();
|
||||
if (baseRim != null) {
|
||||
for (ReferenceDigestValue rdv : repository.findAll()) {
|
||||
if (rdv.getBaseRimId() == baseRim.getId()) {
|
||||
results.add(rdv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRefDigestValueById(UUID rdvId) {
|
||||
repository.getReferenceById(rdvId).archive();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.OrderedListQuerier;
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ReferenceManifestService<T extends ReferenceManifest> extends OrderedListQuerier<T> {
|
||||
|
||||
ReferenceManifest saveReferenceManifest(ReferenceManifest referenceManifest);
|
||||
|
||||
List<ReferenceManifest> fetchReferenceManifests();
|
||||
// DataTablesOutput<ReferenceManifest> fetchReferenceManifests(DataTablesInput input);
|
||||
|
||||
ReferenceManifest updateReferenceManifest(ReferenceManifest referenceManifest, UUID rimId);
|
||||
|
||||
void deleteReferenceManifestById(UUID rimId);
|
||||
|
||||
<T extends ReferenceManifest> Set<T> get(ReferenceManifestSelector referenceManifestSelector);
|
||||
}
|
@ -1,10 +1,15 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.CriteriaModifier;
|
||||
import hirs.attestationca.persist.DBManagerException;
|
||||
import hirs.attestationca.persist.FilteredRecordsList;
|
||||
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@ -13,10 +18,14 @@ import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Log4j2
|
||||
@Service
|
||||
public class ReferenceManifestServiceImpl {
|
||||
public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends DefaultDbService<ReferenceManifest> implements ReferenceManifestService<ReferenceManifest> {
|
||||
|
||||
/**
|
||||
* The variable that establishes a schema factory for xml processing.
|
||||
@ -67,4 +76,69 @@ public class ReferenceManifestServiceImpl {
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReferenceManifest saveReferenceManifest(ReferenceManifest referenceManifest) {
|
||||
return repository.save(referenceManifest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReferenceManifest> fetchReferenceManifests() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does not need to be used directly as it is used by
|
||||
* {@link ReferenceManifestSelector}'s get* methods. Regardless, it may be
|
||||
* used to retrieve ReferenceManifest by other code in this package, given a
|
||||
* configured ReferenceManifestSelector.
|
||||
*
|
||||
* @param referenceManifestSelector a configured
|
||||
* {@link ReferenceManifestSelector} to use for querying
|
||||
* @return the resulting set of ReferenceManifest, possibly empty
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ReferenceManifest> List<T> get(
|
||||
Class<T> classType) {
|
||||
log.info("Getting the full set of Reference Manifest files.");
|
||||
// return new HashSet<>(
|
||||
// (List<T>) getWithCriteria(
|
||||
// referenceManifestSelector.getReferenceManifestClass(),
|
||||
// Collections.singleton(referenceManifestSelector.getCriterion())
|
||||
// )
|
||||
// );
|
||||
return (List<T>) repository.findAll(Sort.sort(classType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReferenceManifest updateReferenceManifest(ReferenceManifest referenceManifest, UUID rimId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteReferenceManifestById(UUID rimId) {
|
||||
repository.deleteById(rimId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ReferenceManifest> Set<T> get(ReferenceManifestSelector referenceManifestSelector) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilteredRecordsList getOrderedList(Class<? extends ReferenceManifest> clazz,
|
||||
String columnToOrder, boolean ascending, int firstResult,
|
||||
int maxResults, String search,
|
||||
Map<String, Boolean> searchableColumns) throws DBManagerException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilteredRecordsList<ReferenceManifest> getOrderedList(Class<? extends ReferenceManifest> clazz,
|
||||
String columnToOrder, boolean ascending,
|
||||
int firstResult, int maxResults, String search,
|
||||
Map<String, Boolean> searchableColumns,
|
||||
CriteriaModifier<ReferenceManifest> criteriaModifier) throws DBManagerException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface SupplyChainValidationService {
|
||||
SupplyChainValidation saveSupplyChainValidation(SupplyChainValidation supplyChainValidation);
|
||||
|
||||
List<SupplyChainValidation> fetchSupplyChainValidations();
|
||||
|
||||
SupplyChainValidation updateSupplyChainValidation(SupplyChainValidation supplyChainValidation, UUID scvId);
|
||||
|
||||
void deleteSupplyChainValidation(UUID scvId);
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
package hirs.attestationca.persist.service;
|
||||
|
||||
import hirs.attestationca.persist.entity.manager.SupplyChainValidationRepository;
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
|
||||
import hirs.utils.BouncyCastleUtils;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Log4j2
|
||||
@Service
|
||||
public class SupplyChainValidationServiceImpl extends DefaultDbService<SupplyChainValidation> implements SupplyChainValidationService {
|
||||
|
||||
@Autowired
|
||||
SupplyChainValidationRepository repository;
|
||||
@Autowired
|
||||
private CertificateService certificateService;
|
||||
|
||||
public SupplyChainValidationServiceImpl(final CertificateService certificateService) {
|
||||
super();
|
||||
this.certificateService = certificateService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SupplyChainValidation saveSupplyChainValidation(SupplyChainValidation supplyChainValidation) {
|
||||
return repository.save(supplyChainValidation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SupplyChainValidation> fetchSupplyChainValidations() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SupplyChainValidation updateSupplyChainValidation(SupplyChainValidation supplyChainValidation, UUID scvId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSupplyChainValidation(UUID scvId) {
|
||||
repository.deleteById(scvId);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to retrieve the entire CA chain (up to a trusted
|
||||
* self-signed certificate) for the given certificate. This method will look
|
||||
* up CA certificates that have a matching issuer organization as the given
|
||||
* certificate, and will perform that operation recursively until all
|
||||
* certificates for all relevant organizations have been retrieved. For that
|
||||
* reason, the returned set of certificates may be larger than the the
|
||||
* single trust chain for the queried certificate, but is guaranteed to
|
||||
* include the trust chain if it exists in this class' CertificateManager.
|
||||
* Returns the certificate authority credentials in a KeyStore.
|
||||
*
|
||||
* @param credential the credential whose CA chain should be retrieved
|
||||
* @return A keystore containing all relevant CA credentials to the given
|
||||
* certificate's organization or null if the keystore can't be assembled
|
||||
*/
|
||||
public KeyStore getCaChain(final Certificate credential) {
|
||||
KeyStore caKeyStore = null;
|
||||
try {
|
||||
caKeyStore = caCertSetToKeystore(getCaChainRec(credential, Collections.emptySet()));
|
||||
} catch (KeyStoreException | IOException e) {
|
||||
log.error("Unable to assemble CA keystore", e);
|
||||
}
|
||||
return caKeyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a recursive method which is used to retrieve the entire CA chain
|
||||
* (up to a trusted self-signed certificate) for the given certificate. This
|
||||
* method will look up CA certificates that have a matching issuer
|
||||
* organization as the given certificate, and will perform that operation
|
||||
* recursively until all certificates for all relevant organizations have
|
||||
* been retrieved. For that reason, the returned set of certificates may be
|
||||
* larger than the the single trust chain for the queried certificate, but
|
||||
* is guaranteed to include the trust chain if it exists in this class'
|
||||
* CertificateManager.
|
||||
* <p>
|
||||
* Implementation notes: 1. Queries for CA certs with a subject org matching
|
||||
* the given (argument's) issuer org 2. Add that org to
|
||||
* queriedOrganizations, so we don't search for that organization again 3.
|
||||
* For each returned CA cert, add that cert to the result set, and recurse
|
||||
* with that as the argument (to go up the chain), if and only if we haven't
|
||||
* already queried for that organization (which prevents infinite loops on
|
||||
* certs with an identical subject and issuer org)
|
||||
*
|
||||
* @param credential the credential whose CA chain should be retrieved
|
||||
* @param previouslyQueriedSubjects a list of organizations to refrain
|
||||
* from querying
|
||||
* @return a Set containing all relevant CA credentials to the given
|
||||
* certificate's organization
|
||||
*/
|
||||
private Set<CertificateAuthorityCredential> getCaChainRec(
|
||||
final Certificate credential,
|
||||
final Set<String> previouslyQueriedSubjects) {
|
||||
CertificateAuthorityCredential skiCA = null;
|
||||
Set<CertificateAuthorityCredential> certAuthsWithMatchingIssuer = new HashSet<>();
|
||||
if (credential.getAuthorityKeyIdentifier() != null
|
||||
&& !credential.getAuthorityKeyIdentifier().isEmpty()) {
|
||||
byte[] bytes = Hex.decode(credential.getAuthorityKeyIdentifier());
|
||||
skiCA = CertificateAuthorityCredential
|
||||
.select(certificateService)
|
||||
.bySubjectKeyIdentifier(bytes).getCertificate();
|
||||
}
|
||||
|
||||
if (skiCA == null) {
|
||||
if (credential.getIssuerSorted() == null
|
||||
|| credential.getIssuerSorted().isEmpty()) {
|
||||
certAuthsWithMatchingIssuer = CertificateAuthorityCredential
|
||||
.select(certificateService)
|
||||
.bySubject(credential.getHolderIssuer())
|
||||
.getCertificates();
|
||||
} else {
|
||||
//Get certificates by subject organization
|
||||
certAuthsWithMatchingIssuer = CertificateAuthorityCredential
|
||||
.select(certificateService)
|
||||
.bySubjectSorted(credential.getIssuerSorted())
|
||||
.getCertificates();
|
||||
}
|
||||
} else {
|
||||
certAuthsWithMatchingIssuer.add(skiCA);
|
||||
}
|
||||
Set<String> queriedOrganizations = new HashSet<>(previouslyQueriedSubjects);
|
||||
queriedOrganizations.add(credential.getHolderIssuer());
|
||||
|
||||
HashSet<CertificateAuthorityCredential> caCreds = new HashSet<>();
|
||||
for (CertificateAuthorityCredential cred : certAuthsWithMatchingIssuer) {
|
||||
caCreds.add(cred);
|
||||
if (!BouncyCastleUtils.x500NameCompare(cred.getHolderIssuer(),
|
||||
cred.getSubject())) {
|
||||
caCreds.addAll(getCaChainRec(cred, queriedOrganizations));
|
||||
}
|
||||
}
|
||||
return caCreds;
|
||||
}
|
||||
|
||||
private KeyStore caCertSetToKeystore(final Set<CertificateAuthorityCredential> certs)
|
||||
throws KeyStoreException, IOException {
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
try {
|
||||
keyStore.load(null, "".toCharArray());
|
||||
for (Certificate cert : certs) {
|
||||
keyStore.setCertificateEntry(cert.getId().toString(), cert.getX509Certificate());
|
||||
}
|
||||
} catch (IOException | CertificateException | NoSuchAlgorithmException e) {
|
||||
throw new IOException("Could not create and populate keystore", e);
|
||||
}
|
||||
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
private boolean checkForMultipleBaseCredentials(final String platformSerialNumber) {
|
||||
boolean multiple = false;
|
||||
PlatformCredential baseCredential = null;
|
||||
|
||||
if (platformSerialNumber != null) {
|
||||
List<PlatformCredential> chainCertificates = PlatformCredential
|
||||
.select(certificateService)
|
||||
.byBoardSerialNumber(platformSerialNumber)
|
||||
.getCertificates().stream().collect(Collectors.toList());
|
||||
|
||||
for (PlatformCredential pc : chainCertificates) {
|
||||
if (baseCredential != null && pc.isPlatformBase()) {
|
||||
multiple = true;
|
||||
} else if (pc.isPlatformBase()) {
|
||||
baseCredential = pc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return multiple;
|
||||
}
|
||||
}
|
@ -0,0 +1,473 @@
|
||||
package hirs.attestationca.persist.service.selector;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.service.CertificateService;
|
||||
import hirs.attestationca.persist.service.CertificateServiceImpl;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class is used to select one or many certificates in conjunction
|
||||
* with a {@link CertificateServiceImpl}. To make use of this object,
|
||||
* use (some CertificateImpl).select(CertificateManager).
|
||||
*
|
||||
* This class loosely follows the builder pattern. It is instantiated with
|
||||
* the type of certificate that should be retrieved. It is possible to
|
||||
* further specify which certificate(s) should be retrieved by using an
|
||||
* instance's by* methods; each call to a by* method will further
|
||||
* restrict the result set. At any time, the results may be retrieved
|
||||
* by using one of the get* methods according to the form the
|
||||
* results should be in.
|
||||
*
|
||||
* If no matching certificates were found for the query, the returned
|
||||
* value may empty or null, depending on the return type.
|
||||
*
|
||||
* For example, to retrieve all platform certificates:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* Set<Certificate> certificates =
|
||||
* certificateManager.select(Certificate.Type.PLATFORM)
|
||||
* .getCertificates();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* To retrieve all CA certificates in a KeyStore:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* KeyStore trustStore =
|
||||
* certificateManager.select(Certificate.Type.CERTIFICATE_AUTHORITY)
|
||||
* .getKeyStore();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* To retrieve all CA certificates matching a certain issuer in X509 format:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* Set<X509Certificate> certificates =
|
||||
* certificateManager.select(Certificate.Type.CERTIFICATE_AUTHORITY)
|
||||
* .byIssuer("CN=Some certain issuer")
|
||||
* .getX509Certificates();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the type of certificate that will be retrieved
|
||||
*/
|
||||
public abstract class CertificateSelector<T extends Certificate> {
|
||||
|
||||
private final CertificateService certificateManager;
|
||||
private final Class<T> certificateClass;
|
||||
|
||||
private final Map<String, Object> fieldValueSelections;
|
||||
private boolean excludeArchivedCertificates;
|
||||
|
||||
/**
|
||||
* Construct a new CertificateSelector that will use the given {@link CertificateServiceImpl} to
|
||||
* retrieve certificates of the given type.
|
||||
*
|
||||
* @param certificateManager the certificate manager to be used to retrieve certificates
|
||||
* @param certificateClass the class of certificate to be retrieved
|
||||
*/
|
||||
public CertificateSelector(
|
||||
final CertificateService certificateManager,
|
||||
final Class<T> certificateClass) {
|
||||
this(certificateManager, certificateClass, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new CertificateSelector that will use the given {@link CertificateService} to
|
||||
* retrieve certificates of the given type.
|
||||
*
|
||||
* @param certificateManager the certificate manager to be used to retrieve certificates
|
||||
* @param certificateClass the class of certificate to be retrieved
|
||||
* @param excludeArchivedCertificates true if excluding archived certificates
|
||||
*/
|
||||
public CertificateSelector(
|
||||
final CertificateService certificateManager,
|
||||
final Class<T> certificateClass, final boolean excludeArchivedCertificates) {
|
||||
Preconditions.checkArgument(
|
||||
certificateManager != null,
|
||||
"certificate manager cannot be null"
|
||||
);
|
||||
|
||||
Preconditions.checkArgument(
|
||||
certificateClass != null,
|
||||
"type cannot be null"
|
||||
);
|
||||
|
||||
this.certificateManager = certificateManager;
|
||||
this.certificateClass = certificateClass;
|
||||
this.fieldValueSelections = new HashMap<>();
|
||||
this.excludeArchivedCertificates = excludeArchivedCertificates;
|
||||
}
|
||||
/**
|
||||
* Specify the entity id that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param uuid the UUID to query
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> byEntityId(final UUID uuid) {
|
||||
setFieldValue(Certificate.ID_FIELD, uuid);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the hash code of the bytes that certificates must match.
|
||||
*
|
||||
* @param certificateHash the hash code of the bytes to query for
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> byHashCode(final int certificateHash) {
|
||||
setFieldValue(Certificate.CERTIFICATE_HASH_FIELD, certificateHash);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a serial number that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param serialNumber the serial number to query
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> bySerialNumber(final BigInteger serialNumber) {
|
||||
setFieldValue(Certificate.SERIAL_NUMBER_FIELD, serialNumber);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a holder serial number that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param holderSerialNumber the holder serial number to query
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> byHolderSerialNumber(final BigInteger holderSerialNumber) {
|
||||
setFieldValue(Certificate.HOLDER_SERIAL_NUMBER_FIELD, holderSerialNumber);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an issuer string that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param issuer certificate issuer string to query, not empty or null
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> byIssuer(final String issuer) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty(issuer),
|
||||
String.format("%s: issuer cannot be null or empty.",
|
||||
this.certificateClass.toString())
|
||||
);
|
||||
|
||||
setFieldValue(Certificate.ISSUER_FIELD, issuer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a subject string that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param subject certificate subject string to query, not empty or null
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> bySubject(final String subject) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty(subject),
|
||||
String.format("%s: subject cannot be null or empty.",
|
||||
this.certificateClass.toString())
|
||||
);
|
||||
|
||||
setFieldValue(Certificate.SUBJECT_FIELD, subject);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the sorted issuer string that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param issuerSorted certificate issuer organization string to query, not empty or null
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> byIssuerSorted(final String issuerSorted) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty(issuerSorted),
|
||||
String.format("%s: issuerSorted cannot be null or empty.",
|
||||
this.certificateClass.toString())
|
||||
);
|
||||
|
||||
setFieldValue(Certificate.ISSUER_SORTED_FIELD, issuerSorted);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the sorted subject string that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param subjectSorted certificate subject organization string to query, not empty or null
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> bySubjectSorted(final String subjectSorted) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty(subjectSorted),
|
||||
String.format("%s: subjectSorted cannot be null or empty.",
|
||||
this.certificateClass.toString())
|
||||
);
|
||||
|
||||
setFieldValue(Certificate.SUBJECT_SORTED_FIELD, subjectSorted);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a public key that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param encodedPublicKey the binary-encoded public key to query, not empty or null
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> byEncodedPublicKey(final byte[] encodedPublicKey) {
|
||||
Preconditions.checkArgument(
|
||||
ArrayUtils.isNotEmpty(encodedPublicKey),
|
||||
String.format("%s: publicKey cannot be null or empty.",
|
||||
this.certificateClass.toString())
|
||||
);
|
||||
|
||||
setFieldValue(
|
||||
Certificate.ENCODED_PUBLIC_KEY_FIELD,
|
||||
Arrays.copyOf(encodedPublicKey, encodedPublicKey.length)
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the authority key identifier to find certificate(s).
|
||||
* @param authorityKeyIdentifier the string of the AKI associated with the certificate.
|
||||
* @return this instance
|
||||
*/
|
||||
public CertificateSelector<T> byAuthorityKeyIdentifier(final String authorityKeyIdentifier) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty(authorityKeyIdentifier),
|
||||
String.format("%s: authorityKeyIdentifier cannot be null or empty.",
|
||||
this.certificateClass.toString())
|
||||
);
|
||||
|
||||
setFieldValue(Certificate.AUTHORITY_KEY_ID_FIELD, authorityKeyIdentifier);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a public key modulus that certificates must have to be considered
|
||||
* as matching.
|
||||
*
|
||||
* @param publicKeyModulus a BigInteger representing a public key's modulus to query not null
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public CertificateSelector<T> byPublicKeyModulus(final BigInteger publicKeyModulus) {
|
||||
Preconditions.checkArgument(
|
||||
publicKeyModulus != null,
|
||||
String.format("%s: Public key modulus cannot be null",
|
||||
this.certificateClass.toString())
|
||||
);
|
||||
|
||||
setFieldValue(
|
||||
Certificate.PUBLIC_KEY_MODULUS_FIELD,
|
||||
publicKeyModulus.toString(Certificate.HEX_BASE)
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a field name and value to match.
|
||||
*
|
||||
* @param name the field name to query
|
||||
* @param value the value to query
|
||||
*/
|
||||
protected void setFieldValue(final String name, final Object value) {
|
||||
Object valueToAssign = value;
|
||||
|
||||
Preconditions.checkArgument(
|
||||
value != null,
|
||||
String.format("field value (%s) cannot be null.", name)
|
||||
);
|
||||
|
||||
if (value instanceof String) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty((String) value),
|
||||
"field value cannot be empty."
|
||||
);
|
||||
}
|
||||
|
||||
if (value instanceof byte[]) {
|
||||
byte[] valueBytes = (byte[]) value;
|
||||
|
||||
Preconditions.checkArgument(
|
||||
ArrayUtils.isNotEmpty(valueBytes),
|
||||
String.format("field value (%s) cannot be empty.", name)
|
||||
);
|
||||
|
||||
valueToAssign = Arrays.copyOf(valueBytes, valueBytes.length);
|
||||
}
|
||||
|
||||
fieldValueSelections.put(name, valueToAssign);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result set as a single {@link Certificate}.
|
||||
* This method is best used when selecting on a unique attribute.
|
||||
* If the result set contains more than one certificate, one is chosen
|
||||
* arbitrarily and returned. If no matching certificates are found,
|
||||
* this method returns null.
|
||||
*
|
||||
* @return a matching certificate or null if none is found
|
||||
*/
|
||||
public T getCertificate() {
|
||||
Set<T> certs = execute();
|
||||
if (certs.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return certs.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result set as a set of {@link Certificate}s.
|
||||
* This method is best used when selecting on non-unique attributes.
|
||||
* Certificates are populated into the set in no specific order.
|
||||
* If no matching certificates are found, the returned Set will be empty.
|
||||
*
|
||||
* @return a Set of matching Certificates, possibly empty
|
||||
*/
|
||||
public Set<T> getCertificates() {
|
||||
return Collections.unmodifiableSet(new HashSet<>(execute()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result set as a single {@link X509Certificate}.
|
||||
* This method is best used when selecting on a unique attribute.
|
||||
* If the result set contains more than one certificate, one is chosen
|
||||
* arbitrarily and returned. If no matching certificates are found,
|
||||
* this method returns null.
|
||||
*
|
||||
* @return a matching certificate or null if none is found
|
||||
* @throws IOException if there is a problem reconstructing the X509Certificate
|
||||
*/
|
||||
public X509Certificate getX509Certificate() throws IOException {
|
||||
Certificate cert = getCertificate();
|
||||
if (cert == null) {
|
||||
return null;
|
||||
}
|
||||
return cert.getX509Certificate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result set as a set of {@link X509Certificate}s.
|
||||
* This method is best used when selecting on non-unique attributes.
|
||||
* Certificates are populated into the set in no specific order.
|
||||
* If no matching certificates are found, the returned Set will be empty.
|
||||
*
|
||||
* @return a Set of matching Certificates, possibly empty
|
||||
* @throws IOException if there is a problem reconstructing the X509Certificates
|
||||
*/
|
||||
public Set<X509Certificate> getX509Certificates() throws IOException {
|
||||
Set<X509Certificate> certs = new HashSet<>();
|
||||
for (Certificate cert : getCertificates()) {
|
||||
certs.add(cert.getX509Certificate());
|
||||
}
|
||||
return Collections.unmodifiableSet(certs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result set populated into a {@link KeyStore}.
|
||||
* Certificates are populated into a JKS-formatted KeyStore, with their aliases
|
||||
* set to their unique identifiers.
|
||||
* If no matching certificates are found, the returned KeyStore will be empty.
|
||||
*
|
||||
* @return a KeyStore populated with the matching certificates, if any
|
||||
* @throws KeyStoreException if there is a problem instantiating a JKS-formatted KeyStore
|
||||
* @throws IOException if there is a problem populating the keystore
|
||||
*/
|
||||
public KeyStore getKeyStore() throws KeyStoreException, IOException {
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
try {
|
||||
keyStore.load(null, "".toCharArray());
|
||||
for (Certificate cert : getCertificates()) {
|
||||
keyStore.setCertificateEntry(cert.getId().toString(), cert.getX509Certificate());
|
||||
}
|
||||
} catch (IOException | CertificateException | NoSuchAlgorithmException e) {
|
||||
throw new IOException("Could not create and populate keystore", e);
|
||||
}
|
||||
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the criterion that can be used to query for certificates matching the configuration
|
||||
* of this {@link CertificateSelector}.
|
||||
*
|
||||
* @return a Criterion that can be used to query for certificates matching the configuration of
|
||||
* this instance
|
||||
*/
|
||||
Predicate[] getCriterion(final CriteriaBuilder criteriaBuilder) {
|
||||
Predicate[] predicates = new Predicate[fieldValueSelections.size()];
|
||||
CriteriaQuery<T> query = criteriaBuilder.createQuery(getCertificateClass());
|
||||
Root<T> root = query.from(getCertificateClass());
|
||||
|
||||
int i = 0;
|
||||
for (Map.Entry<String, Object> fieldValueEntry : fieldValueSelections.entrySet()) {
|
||||
predicates[i++] = criteriaBuilder.equal(root.get(fieldValueEntry.getKey()), fieldValueEntry.getValue());
|
||||
}
|
||||
|
||||
if (this.excludeArchivedCertificates) {
|
||||
predicates[i] = criteriaBuilder.isNull(root.get(Certificate.ARCHIVE_FIELD));
|
||||
}
|
||||
|
||||
return predicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the certificate class that this instance will query
|
||||
*/
|
||||
public Class<T> getCertificateClass() {
|
||||
return certificateClass;
|
||||
}
|
||||
|
||||
// construct and execute query
|
||||
private Set<T> execute() {
|
||||
return certificateManager.get(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the selector to query for archived and unarchived certificates.
|
||||
* @return the selector
|
||||
*/
|
||||
public CertificateSelector<T> includeArchived() {
|
||||
excludeArchivedCertificates = false;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,233 @@
|
||||
package hirs.attestationca.persist.service.selector;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestService;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class is used to select one or many RIMs in conjunction
|
||||
* with a {@link ReferenceManifestService}. To make use of this object,
|
||||
* use (some ReferenceManifest).select(ReferenceManifestManager).
|
||||
*
|
||||
* @param <T> the type of Reference Integrity Manifest that will be retrieved.
|
||||
*/
|
||||
public abstract class ReferenceManifestSelector<T extends ReferenceManifest> {
|
||||
/**
|
||||
* String representing the database field for the manufacturer.
|
||||
*/
|
||||
public static final String PLATFORM_MANUFACTURER = "platformManufacturer";
|
||||
/**
|
||||
* String representing the database field for the manufacturer id.
|
||||
*/
|
||||
public static final String PLATFORM_MANUFACTURER_ID = "platformManufacturerId";
|
||||
/**
|
||||
* String representing the database field for the model.
|
||||
*/
|
||||
public static final String PLATFORM_MODEL = "platformModel";
|
||||
/**
|
||||
* String representing the database field for the filename.
|
||||
*/
|
||||
public static final String RIM_FILENAME_FIELD = "fileName";
|
||||
private static final String RIM_TYPE_FIELD = "rimType";
|
||||
|
||||
private final ReferenceManifestService referenceManifestManager;
|
||||
private final Class<T> referenceTypeClass;
|
||||
|
||||
private final Map<String, Object> fieldValueSelections;
|
||||
private boolean excludeArchivedRims;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* @param referenceManifestManager the RIM manager to be used to retrieve RIMs
|
||||
* @param referenceTypeClass the type of Reference Manifest to process.
|
||||
*/
|
||||
public ReferenceManifestSelector(final ReferenceManifestService referenceManifestManager,
|
||||
final Class<T> referenceTypeClass) {
|
||||
this(referenceManifestManager, referenceTypeClass, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Constructor for the Selector.
|
||||
*
|
||||
* @param referenceManifestManager the RIM manager to be used to retrieve RIMs
|
||||
* @param referenceTypeClass the type of Reference Manifest to process.
|
||||
* @param excludeArchivedRims true if excluding archived RIMs
|
||||
*/
|
||||
public ReferenceManifestSelector(final ReferenceManifestService referenceManifestManager,
|
||||
final Class<T> referenceTypeClass,
|
||||
final boolean excludeArchivedRims) {
|
||||
Preconditions.checkArgument(
|
||||
referenceManifestManager != null,
|
||||
"reference manifest manager cannot be null"
|
||||
);
|
||||
|
||||
Preconditions.checkArgument(
|
||||
referenceTypeClass != null,
|
||||
"type cannot be null"
|
||||
);
|
||||
|
||||
this.referenceManifestManager = referenceManifestManager;
|
||||
this.referenceTypeClass = referenceTypeClass;
|
||||
this.excludeArchivedRims = excludeArchivedRims;
|
||||
this.fieldValueSelections = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the entity id that rims must have to be considered as matching.
|
||||
*
|
||||
* @param uuid the UUID to query
|
||||
* @return this instance (for chaining further calls)
|
||||
*/
|
||||
public ReferenceManifestSelector<T> byEntityId(final UUID uuid) {
|
||||
setFieldValue(Certificate.ID_FIELD, uuid);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the file name of the object to grab.
|
||||
* @param fileName the name of the file associated with the rim
|
||||
* @return instance of the manifest in relation to the filename.
|
||||
*/
|
||||
public ReferenceManifestSelector<T> byFileName(final String fileName) {
|
||||
setFieldValue(RIM_FILENAME_FIELD, fileName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the RIM Type to match.
|
||||
* @param rimType the type of rim
|
||||
* @return this instance
|
||||
*/
|
||||
public ReferenceManifestSelector<T> byRimType(final String rimType) {
|
||||
setFieldValue(RIM_TYPE_FIELD, rimType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a field name and value to match.
|
||||
*
|
||||
* @param name the field name to query
|
||||
* @param value the value to query
|
||||
*/
|
||||
protected void setFieldValue(final String name, final Object value) {
|
||||
Object valueToAssign = value;
|
||||
|
||||
Preconditions.checkArgument(
|
||||
value != null,
|
||||
String.format("field value (%s) cannot be null.", name)
|
||||
);
|
||||
|
||||
if (value instanceof String) {
|
||||
Preconditions.checkArgument(
|
||||
StringUtils.isNotEmpty((String) value),
|
||||
"field value cannot be empty."
|
||||
);
|
||||
}
|
||||
|
||||
if (value instanceof byte[]) {
|
||||
byte[] valueBytes = (byte[]) value;
|
||||
|
||||
Preconditions.checkArgument(
|
||||
ArrayUtils.isNotEmpty(valueBytes),
|
||||
String.format("field value (%s) cannot be empty.", name)
|
||||
);
|
||||
|
||||
valueToAssign = Arrays.copyOf(valueBytes, valueBytes.length);
|
||||
}
|
||||
|
||||
fieldValueSelections.put(name, valueToAssign);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result set as a single
|
||||
* {@link ReferenceManifest}. This method is best used
|
||||
* when selecting on a unique attribute. If the result set contains more
|
||||
* than one RIM, one is chosen arbitrarily and returned. If no matching RIMs
|
||||
* are found, this method returns null.
|
||||
*
|
||||
* @return a matching RIM or null if none is found
|
||||
*/
|
||||
public T getRIM() {
|
||||
Set<T> rims = execute();
|
||||
if (rims.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return rims.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result set as a set of
|
||||
* {@link ReferenceManifest}s. This method is best used
|
||||
* when selecting on non-unique attributes. ReferenceManifests are populated
|
||||
* into the set in no specific order. If no matching certificates are found,
|
||||
* the returned Set will be empty.
|
||||
*
|
||||
* @return a Set of matching RIMs, possibly empty
|
||||
*/
|
||||
public Set<T> getRIMs() {
|
||||
return Set.copyOf(execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the criterion that can be used to query for rims matching the
|
||||
* configuration of this {@link ReferenceManifestSelector}.
|
||||
*
|
||||
* @return a Criterion that can be used to query for rims matching the
|
||||
* configuration of this instance
|
||||
*/
|
||||
Predicate[] getCriterion(final CriteriaBuilder criteriaBuilder) {
|
||||
Predicate[] predicates = new Predicate[fieldValueSelections.size()];
|
||||
CriteriaQuery<T> query = criteriaBuilder.createQuery(getReferenceManifestClass());
|
||||
Root<T> root = query.from(getReferenceManifestClass());
|
||||
|
||||
int i = 0;
|
||||
for (Map.Entry<String, Object> fieldValueEntry : fieldValueSelections.entrySet()) {
|
||||
predicates[i++] = criteriaBuilder.equal(root.get(fieldValueEntry.getKey()), fieldValueEntry.getValue());
|
||||
}
|
||||
|
||||
if (this.excludeArchivedRims) {
|
||||
predicates[i] = criteriaBuilder.isNull(root.get(Certificate.ARCHIVE_FIELD));
|
||||
}
|
||||
|
||||
return predicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rim class that this instance will query
|
||||
*/
|
||||
public Class<T> getReferenceManifestClass() {
|
||||
return this.referenceTypeClass;
|
||||
}
|
||||
|
||||
// construct and execute query
|
||||
private Set<T> execute() {
|
||||
Set<T> results = this.referenceManifestManager.get(this);
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the selector to query for archived and unarchived rims.
|
||||
*
|
||||
* @return the selector
|
||||
*/
|
||||
public ReferenceManifestSelector<T> includeArchived() {
|
||||
this.excludeArchivedRims = false;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package hirs.attestationca.persist.validation;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
|
||||
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
|
||||
import hirs.attestationca.persist.enums.AppraisalStatus;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A class used to support supply chain validation by performing the actual
|
||||
* validation of credentials.
|
||||
*/
|
||||
public interface CredentialValidator {
|
||||
/**
|
||||
* Checks if the platform credential is valid.
|
||||
*
|
||||
* @param pc The platform credential to verify.
|
||||
* @param trustStore trust store holding trusted certificates.
|
||||
* @param acceptExpired whether or not to accept expired certificates as valid.
|
||||
* @return The result of the validation.
|
||||
*/
|
||||
AppraisalStatus validatePlatformCredential(PlatformCredential pc,
|
||||
KeyStore trustStore,
|
||||
boolean acceptExpired);
|
||||
|
||||
/**
|
||||
* Checks if the platform credential's attributes are valid.
|
||||
* @param pc The platform credential to verify.
|
||||
* @param deviceInfoReport Report containing the serial numbers of the platform to be validated.
|
||||
* @param ec The endorsement credential supplied from the same identity request as
|
||||
* the platform credential.
|
||||
* @return The result of the validation.
|
||||
*/
|
||||
AppraisalStatus validatePlatformCredentialAttributes(PlatformCredential pc,
|
||||
DeviceInfoReport deviceInfoReport,
|
||||
EndorsementCredential ec);
|
||||
|
||||
/**
|
||||
* Checks if the delta credential's attributes are valid.
|
||||
* @param delta the delta credential to verify
|
||||
* @param deviceInfoReport The device info report containing
|
||||
* serial number of the platform to be validated.
|
||||
* @param base the base credential from the same identity request
|
||||
* as the delta credential.
|
||||
* @param deltaMapping delta certificates associated with the
|
||||
* delta supply validation.
|
||||
* @return the result of the validation.
|
||||
*/
|
||||
AppraisalStatus validateDeltaPlatformCredentialAttributes(PlatformCredential delta,
|
||||
DeviceInfoReport deviceInfoReport,
|
||||
PlatformCredential base,
|
||||
Map<PlatformCredential,
|
||||
SupplyChainValidation> deltaMapping);
|
||||
/**
|
||||
* Checks if the endorsement credential is valid.
|
||||
*
|
||||
* @param ec the endorsement credential to verify.
|
||||
* @param trustStore trust store holding trusted trusted certificates.
|
||||
* @param acceptExpired whether or not to accept expired certificates as valid.
|
||||
* @return the result of the validation.
|
||||
*/
|
||||
AppraisalStatus validateEndorsementCredential(EndorsementCredential ec,
|
||||
KeyStore trustStore,
|
||||
boolean acceptExpired);
|
||||
}
|
@ -0,0 +1,445 @@
|
||||
package hirs.attestationca.persist.validation;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import jakarta.xml.bind.UnmarshalException;
|
||||
import jakarta.xml.bind.Unmarshaller;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.crypto.AlgorithmMethod;
|
||||
import javax.xml.crypto.KeySelector;
|
||||
import javax.xml.crypto.KeySelectorException;
|
||||
import javax.xml.crypto.KeySelectorResult;
|
||||
import javax.xml.crypto.MarshalException;
|
||||
import javax.xml.crypto.XMLCryptoContext;
|
||||
import javax.xml.crypto.XMLStructure;
|
||||
import javax.xml.crypto.dsig.XMLSignature;
|
||||
import javax.xml.crypto.dsig.XMLSignatureException;
|
||||
import javax.xml.crypto.dsig.XMLSignatureFactory;
|
||||
import javax.xml.crypto.dsig.dom.DOMValidateContext;
|
||||
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
|
||||
import javax.xml.crypto.dsig.keyinfo.X509Data;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Key;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This class handles validation functions of RIM files.
|
||||
* Currently supports validation of support RIM hashes and
|
||||
* base RIM signatures.
|
||||
*/
|
||||
@Log4j2
|
||||
public class ReferenceManifestValidator {
|
||||
private static final String SIGNATURE_ALGORITHM_RSA_SHA256 =
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
||||
private static final String SCHEMA_PACKAGE = "hirs.utils.xjc";
|
||||
private static final String SCHEMA_URL = "swid_schema.xsd";
|
||||
private static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI;
|
||||
private static final String IDENTITY_TRANSFORM = "identity_transform.xslt";
|
||||
private static final String SHA256 = "SHA-256";
|
||||
private static final int EIGHT_BIT_MASK = 0xff;
|
||||
private static final int LEFT_SHIFT = 0x100;
|
||||
private static final int RADIX = 16;
|
||||
|
||||
private Document rim;
|
||||
private Unmarshaller unmarshaller;
|
||||
private PublicKey publicKey;
|
||||
private Schema schema;
|
||||
private String subjectKeyIdentifier;
|
||||
private boolean signatureValid, supportRimValid;
|
||||
|
||||
/**
|
||||
* Setter for the RIM to be validated. The ReferenceManifest object is converted into a
|
||||
* Document for processing.
|
||||
*
|
||||
* @param rim ReferenceManifest object
|
||||
*/
|
||||
public void setRim(final ReferenceManifest rim) {
|
||||
try {
|
||||
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(
|
||||
new ByteArrayInputStream(rim.getRimBytes()))));
|
||||
this.rim = doc;
|
||||
} catch (IOException e) {
|
||||
log.error("Error while unmarshalling rim bytes: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for signatureValid.
|
||||
*
|
||||
* @return true if valid, false if not.
|
||||
*/
|
||||
public boolean isSignatureValid() {
|
||||
return signatureValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for supportRimValid.
|
||||
*
|
||||
* @return true if valid, false if not.
|
||||
*/
|
||||
public boolean isSupportRimValid() {
|
||||
return supportRimValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for certificate PublicKey.
|
||||
*
|
||||
* @return PublicKey
|
||||
*/
|
||||
public PublicKey getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for subjectKeyIdentifier.
|
||||
*
|
||||
* @return subjectKeyIdentifier
|
||||
*/
|
||||
public String getSubjectKeyIdentifier() {
|
||||
return subjectKeyIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* This default constructor creates the Schema object from SCHEMA_URL immediately to save
|
||||
* time during validation calls later.
|
||||
*/
|
||||
public ReferenceManifestValidator() {
|
||||
try {
|
||||
InputStream is = ReferenceManifestValidator.class
|
||||
.getClassLoader().getResourceAsStream(SCHEMA_URL);
|
||||
SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE);
|
||||
schema = schemaFactory.newSchema(new StreamSource(is));
|
||||
rim = null;
|
||||
signatureValid = false;
|
||||
supportRimValid = false;
|
||||
publicKey = null;
|
||||
subjectKeyIdentifier = "(not found)";
|
||||
} catch (SAXException e) {
|
||||
log.warn("Error setting schema for validation!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method attempts to validate the signature element of the instance's RIM
|
||||
* using a given cert. The cert is compared to either the RIM's embedded certificate
|
||||
* or the RIM's subject key identifier. If the cert is matched then validation proceeds,
|
||||
* otherwise validation ends.
|
||||
*
|
||||
* @param cert the cert to be checked against the RIM
|
||||
* @return true if the signature element is validated, false otherwise
|
||||
*/
|
||||
@SuppressWarnings("magicnumber")
|
||||
public boolean validateXmlSignature(final CertificateAuthorityCredential cert) {
|
||||
DOMValidateContext context = null;
|
||||
try {
|
||||
NodeList nodes = rim.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
||||
if (nodes.getLength() == 0) {
|
||||
log.error("Cannot validate RIM, signature element not found!");
|
||||
return false;
|
||||
}
|
||||
NodeList certElement = rim.getElementsByTagName("X509Certificate");
|
||||
if (certElement.getLength() > 0) {
|
||||
X509Certificate embeddedCert = parseCertFromPEMString(
|
||||
certElement.item(0).getTextContent());
|
||||
if (embeddedCert != null) {
|
||||
subjectKeyIdentifier = getCertificateSubjectKeyIdentifier(embeddedCert);
|
||||
if (Arrays.equals(embeddedCert.getPublicKey().getEncoded(),
|
||||
cert.getEncodedPublicKey())) {
|
||||
context = new DOMValidateContext(new X509KeySelector(), nodes.item(0));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
subjectKeyIdentifier = getKeyName(rim);
|
||||
if (subjectKeyIdentifier.equals(cert.getSubjectKeyIdString())) {
|
||||
context = new DOMValidateContext(cert.getX509Certificate().getPublicKey(),
|
||||
nodes.item(0));
|
||||
}
|
||||
}
|
||||
if (context != null) {
|
||||
publicKey = cert.getX509Certificate().getPublicKey();
|
||||
signatureValid = validateSignedXMLDocument(context);
|
||||
return signatureValid;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Error while parsing certificate data: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the SHA256 hash of the input byte array and compares it against
|
||||
* the value passed in.
|
||||
*
|
||||
* @param input byte array to hash.
|
||||
* @param expected value to compare against.
|
||||
*/
|
||||
public void validateSupportRimHash(final byte[] input, final String expected) {
|
||||
String calculatedHash = getHashValue(input, SHA256);
|
||||
supportRimValid = calculatedHash.equals(expected);
|
||||
if (!supportRimValid) {
|
||||
log.info("Unmatched support RIM hash! Expected: " + expected
|
||||
+ ", actual: " + calculatedHash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the digest of a byte array based on the hashing algorithm passed in.
|
||||
*
|
||||
* @param input byte array.
|
||||
* @param sha hash algorithm.
|
||||
* @return String digest.
|
||||
*/
|
||||
private String getHashValue(final byte[] input, final String sha) {
|
||||
String resultString = null;
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance(sha);
|
||||
byte[] bytes = md.digest(input);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
sb.append(Integer.toString((bytes[i] & EIGHT_BIT_MASK)
|
||||
+ LEFT_SHIFT, RADIX).substring(1));
|
||||
}
|
||||
resultString = sb.toString();
|
||||
} catch (NoSuchAlgorithmException grex) {
|
||||
log.warn(grex.getMessage());
|
||||
}
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
private boolean validateSignedXMLDocument(final DOMValidateContext context) {
|
||||
try {
|
||||
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
|
||||
XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
|
||||
return signature.validate(context);
|
||||
} catch (MarshalException e) {
|
||||
log.warn("Error while unmarshalling XML signature: " + e.getMessage());
|
||||
} catch (XMLSignatureException e) {
|
||||
log.warn("Error while validating XML signature: " + e.getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This internal class handles selecting an X509 certificate embedded in a KeyInfo element.
|
||||
* It is passed as a parameter to a DOMValidateContext that uses it to validate
|
||||
* an XML signature.
|
||||
*/
|
||||
public static class X509KeySelector extends KeySelector {
|
||||
/**
|
||||
* This method selects a public key for validation.
|
||||
* PKs are parsed preferentially from the following elements:
|
||||
* - X509Data
|
||||
* - KeyValue
|
||||
* The parsed PK is then verified based on the provided algorithm before
|
||||
* being returned in a KeySelectorResult.
|
||||
*
|
||||
* @param keyinfo object containing the cert.
|
||||
* @param purpose purpose.
|
||||
* @param algorithm algorithm.
|
||||
* @param context XMLCryptoContext.
|
||||
* @return KeySelectorResult holding the PublicKey.
|
||||
* @throws KeySelectorException exception.
|
||||
*/
|
||||
public KeySelectorResult select(final KeyInfo keyinfo,
|
||||
final KeySelector.Purpose purpose,
|
||||
final AlgorithmMethod algorithm,
|
||||
final XMLCryptoContext context)
|
||||
throws KeySelectorException {
|
||||
Iterator keyinfoItr = keyinfo.getContent().iterator();
|
||||
while (keyinfoItr.hasNext()) {
|
||||
XMLStructure element = (XMLStructure) keyinfoItr.next();
|
||||
if (element instanceof X509Data) {
|
||||
X509Data data = (X509Data) element;
|
||||
Iterator dataItr = data.getContent().iterator();
|
||||
while (dataItr.hasNext()) {
|
||||
Object object = dataItr.next();
|
||||
if (object instanceof X509Certificate) {
|
||||
final PublicKey publicKey = ((X509Certificate) object).getPublicKey();
|
||||
if (areAlgorithmsEqual(algorithm.getAlgorithm(),
|
||||
publicKey.getAlgorithm())) {
|
||||
return new ReferenceManifestValidator.X509KeySelector
|
||||
.RIMKeySelectorResult(publicKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new KeySelectorException("No key found!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if two strings refer to the same algorithm.
|
||||
*
|
||||
* @param uri string 1
|
||||
* @param name string 2
|
||||
* @return true if equal, false if not
|
||||
*/
|
||||
public boolean areAlgorithmsEqual(final String uri, final String name) {
|
||||
return uri.equals(SIGNATURE_ALGORITHM_RSA_SHA256) && name.equalsIgnoreCase("RSA");
|
||||
}
|
||||
|
||||
/**
|
||||
* This internal class creates a KeySelectorResult from the public key.
|
||||
*/
|
||||
private static class RIMKeySelectorResult implements KeySelectorResult {
|
||||
private Key key;
|
||||
|
||||
RIMKeySelectorResult(final Key key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method extracts certificate bytes from a string. The bytes are assumed to be
|
||||
* PEM format, and a header and footer are concatenated with the input string to
|
||||
* facilitate proper parsing.
|
||||
*
|
||||
* @param pemString the input string
|
||||
* @return an X509Certificate created from the string, or null
|
||||
* @throws Exception if certificate cannot be successfully parsed
|
||||
*/
|
||||
private X509Certificate parseCertFromPEMString(final String pemString) throws Exception {
|
||||
String certificateHeader = "-----BEGIN CERTIFICATE-----";
|
||||
String certificateFooter = "-----END CERTIFICATE-----";
|
||||
try {
|
||||
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
InputStream inputStream = new ByteArrayInputStream((certificateHeader
|
||||
+ System.lineSeparator()
|
||||
+ pemString
|
||||
+ System.lineSeparator()
|
||||
+ certificateFooter).getBytes("UTF-8"));
|
||||
return (X509Certificate) factory.generateCertificate(inputStream);
|
||||
} catch (CertificateException e) {
|
||||
log.warn("Error creating CertificateFactory instance: " + e.getMessage());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn("Error while parsing cert from PEM string: " + e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the subjectKeyIdentifier from a given X509Certificate.
|
||||
*
|
||||
* @param certificate the cert to pull the subjectKeyIdentifier from
|
||||
* @return the String representation of the subjectKeyIdentifier
|
||||
* @throws IOException
|
||||
*/
|
||||
private String getCertificateSubjectKeyIdentifier(final X509Certificate certificate)
|
||||
throws IOException {
|
||||
String decodedValue;
|
||||
byte[] extension = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId());
|
||||
if (extension != null && extension.length > 0) {
|
||||
decodedValue = JcaX509ExtensionUtils.parseExtensionValue(extension).toString();
|
||||
} else {
|
||||
decodedValue = " "; //Unlikely that a proper X509Certificate does not have a skid
|
||||
}
|
||||
return decodedValue.substring(1); //Drop the # at the beginning of the string
|
||||
}
|
||||
|
||||
/**
|
||||
* This method parses the subject key identifier from the KeyName element of a signature.
|
||||
*
|
||||
* @param doc
|
||||
* @return SKID if found, or an empty string.
|
||||
*/
|
||||
private String getKeyName(final Document doc) {
|
||||
NodeList keyName = doc.getElementsByTagName("KeyName");
|
||||
if (keyName.getLength() > 0) {
|
||||
return keyName.item(0).getTextContent();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method validates the Document against the schema.
|
||||
*
|
||||
* @param doc of the input swidtag.
|
||||
* @return document validated against the schema.
|
||||
*/
|
||||
private Document validateSwidtagSchema(final Document doc) {
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(SCHEMA_PACKAGE);
|
||||
unmarshaller = jaxbContext.createUnmarshaller();
|
||||
unmarshaller.setSchema(schema);
|
||||
unmarshaller.unmarshal(doc);
|
||||
} catch (UnmarshalException e) {
|
||||
log.warn("Error validating swidtag file!");
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("Input file empty.");
|
||||
} catch (JAXBException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method strips all whitespace from an xml file, including indents and spaces
|
||||
* added for human-readability.
|
||||
*
|
||||
* @param source of the input xml.
|
||||
* @return Document representation of the xml.
|
||||
*/
|
||||
private Document removeXMLWhitespace(final StreamSource source) throws IOException {
|
||||
TransformerFactory tf = TransformerFactory.newInstance();
|
||||
Source identitySource = new StreamSource(
|
||||
ReferenceManifestValidator.class.getClassLoader()
|
||||
.getResourceAsStream(IDENTITY_TRANSFORM));
|
||||
Document doc = null;
|
||||
try {
|
||||
Transformer transformer = tf.newTransformer(identitySource);
|
||||
DOMResult result = new DOMResult();
|
||||
transformer.transform(source, result);
|
||||
doc = (Document) result.getNode();
|
||||
} catch (TransformerConfigurationException e) {
|
||||
log.warn("Error configuring transformer!");
|
||||
e.printStackTrace();
|
||||
} catch (TransformerException e) {
|
||||
log.warn("Error transforming input!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package hirs.attestationca.persist.validation;
|
||||
|
||||
/**
|
||||
* This class represents exceptions thrown by the SupplyChainValidator class.
|
||||
*/
|
||||
public class SupplyChainValidatorException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 8563981058518865230L;
|
||||
|
||||
/**
|
||||
* Creates a new <code>SupplyChainValidatorException</code> that has the message
|
||||
* <code>message</code> and <code>Throwable</code> cause <code>cause</code>.
|
||||
*
|
||||
* @param message
|
||||
* exception message
|
||||
* @param cause
|
||||
* root cause
|
||||
*/
|
||||
public SupplyChainValidatorException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>SupplyChainValidatorException</code> that has the <code>String</code>
|
||||
* message <code>message</code>.
|
||||
*
|
||||
* @param message
|
||||
* exception message
|
||||
*/
|
||||
public SupplyChainValidatorException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>SupplyChainValidatorException</code> that has the <code>Throwable</code>
|
||||
* cause <code>cause</code>.
|
||||
*
|
||||
* @param cause
|
||||
* root cause
|
||||
*/
|
||||
public SupplyChainValidatorException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@ -13,47 +13,4 @@ public class HIRSDbInitializer implements ServletContextListener {
|
||||
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.");
|
||||
// }
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package hirs.attestationca.portal;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
@ -17,15 +19,29 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Properties;
|
||||
|
||||
@Log4j2
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@PropertySource({ "classpath:hibernate.properties" })
|
||||
@ComponentScan({ "hirs.attestationca.portal.page" })
|
||||
@EnableJpaRepositories(basePackages = "hirs.attestationca.persist")
|
||||
@PropertySource({ "classpath:hibernate.properties", "classpath:portal.properties" })
|
||||
@ComponentScan({ "hirs.attestationca.portal.page.controllers", "hirs.attestationca.persist.entity" })
|
||||
@EnableJpaRepositories(basePackages = "hirs.attestationca.persist.entity.manager")
|
||||
public class PersistenceJPAConfig {
|
||||
|
||||
@Value("${aca.directories.certificates}")
|
||||
private String certificatesLocation;
|
||||
|
||||
@Value("${aca.keyStore.location}")
|
||||
private String keyStoreLocation;
|
||||
|
||||
@Value("${aca.keyStore.password:''}")
|
||||
private String keyStorePassword;
|
||||
|
||||
@Value("${aca.keyStore.alias}")
|
||||
private String keyAlias;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@ -53,6 +69,97 @@ public class PersistenceJPAConfig {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization of the ACA. Detects environment and runs configuration
|
||||
* methods as required. This method is intended to be invoked by the Spring
|
||||
* application context.
|
||||
*/
|
||||
// @PostConstruct
|
||||
// void initialize() {
|
||||
// // ensure that Bouncy Castle is registered as a security provider
|
||||
// Security.addProvider(new BouncyCastleProvider());
|
||||
//
|
||||
// // obtain path to ACA configuration
|
||||
// Path certificatesPath = Paths.get(certificatesLocation);
|
||||
//
|
||||
// // create base directories if they do not exist
|
||||
// try {
|
||||
// Files.createDirectories(certificatesPath);
|
||||
// } catch (IOException ioEx) {
|
||||
// throw new BeanInitializationException(
|
||||
// "Encountered error while initializing ACA directories: " + ioEx.getMessage(), ioEx);
|
||||
// }
|
||||
//
|
||||
// // create the ACA key store if it doesn't exist
|
||||
// Path keyStorePath = Paths.get(keyStoreLocation);
|
||||
//// if (!Files.exists(keyStorePath)) {
|
||||
//// throw new IllegalStateException(
|
||||
//// String.format("ACA Key Store not found at %s. Consult the HIRS User "
|
||||
//// + "Guide for ACA installation instructions.", keyStoreLocation));
|
||||
//// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* @return the {@link X509Certificate} of the ACA
|
||||
*/
|
||||
// @Bean
|
||||
// public X509Certificate acaCertificate() {
|
||||
// KeyStore keyStore = keyStore();
|
||||
//
|
||||
// try {
|
||||
// X509Certificate acaCertificate = (X509Certificate) keyStore.getCertificate(keyAlias);
|
||||
//
|
||||
// // break early if the certificate is not available.
|
||||
// if (acaCertificate == null) {
|
||||
// throw new BeanInitializationException(String.format("Certificate with alias "
|
||||
// + "%s was not in KeyStore %s. Ensure that the KeyStore has the "
|
||||
// + "specified certificate. ", keyAlias, keyStoreLocation));
|
||||
// }
|
||||
//
|
||||
// return acaCertificate;
|
||||
// } catch (KeyStoreException ksEx) {
|
||||
// throw new BeanInitializationException("Encountered error loading ACA certificate "
|
||||
// + "from key store: " + ksEx.getMessage(), ksEx);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* @return the {@link java.security.KeyStore} that contains the certificates
|
||||
* for the ACA.
|
||||
*/
|
||||
// @Bean
|
||||
// public KeyStore keyStore() {
|
||||
// Path keyStorePath = Paths.get(keyStoreLocation);
|
||||
//
|
||||
// // creating empty store
|
||||
// String storePassword = "storePassword";
|
||||
// String storeName = "emptyStore.jks";
|
||||
// String storeType = "jks";
|
||||
//
|
||||
// // attempt to open the key store. if that fails, log a meaningful message before failing.
|
||||
//// try {
|
||||
//// KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
//// keyStore.load(Files.newInputStream(keyStorePath), keyStorePassword.toCharArray());
|
||||
//
|
||||
// // empty
|
||||
// try (FileOutputStream fileOutputStream = new FileOutputStream(storeName)) {
|
||||
// KeyStore keyStore = KeyStore.getInstance(storeType);
|
||||
// keyStore.load(null, storePassword.toCharArray());
|
||||
//// keyStore.setCertificateEntry(keyAlias,);
|
||||
// keyStore.store(fileOutputStream, storePassword.toCharArray());
|
||||
//
|
||||
//
|
||||
// return keyStore;
|
||||
// } catch (Exception e) {
|
||||
// log.error(String.format(
|
||||
// "Encountered error while loading ACA key store. The most common issue is "
|
||||
// + "that configured password does not work on the configured key"
|
||||
// + " store %s.", keyStorePath));
|
||||
// log.error(String.format("Exception message: %s", e.getMessage()));
|
||||
// throw new BeanInitializationException(e.getMessage(), e);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
final JpaTransactionManager transactionManager = new JpaTransactionManager();
|
||||
@ -76,11 +183,11 @@ public class PersistenceJPAConfig {
|
||||
|
||||
return hibernateProperties;
|
||||
}
|
||||
//
|
||||
// @Bean(name="default-settings")
|
||||
// public SupplyChainSettings supplyChainSettings() {
|
||||
// SupplyChainSettings scSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
|
||||
//
|
||||
// return scSettings;
|
||||
// }
|
||||
|
||||
@Bean(name="default-settings")
|
||||
public SupplyChainSettings supplyChainSettings() {
|
||||
SupplyChainSettings scSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
|
||||
|
||||
return scSettings;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
package hirs.attestationca.portal.datatables;
|
||||
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Java representation of a jQuery DataTables Column.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor(access = AccessLevel.PUBLIC)
|
||||
public class Column {
|
||||
|
||||
/**
|
||||
* Column's data source.
|
||||
*
|
||||
* @see http://datatables.net/reference/option/columns.data
|
||||
*/
|
||||
@NotBlank
|
||||
private String data;
|
||||
|
||||
/**
|
||||
* Column's name.
|
||||
*
|
||||
* @see http://datatables.net/reference/option/columns.name
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Flag to indicate if this column is searchable (true) or not (false).
|
||||
*
|
||||
* @see http://datatables.net/reference/option/columns.searchable
|
||||
*/
|
||||
@NotNull
|
||||
private boolean searchable;
|
||||
|
||||
/**
|
||||
* Flag to indicate if this column is orderable (true) or not (false).
|
||||
*
|
||||
* @see http://datatables.net/reference/option/columns.orderable
|
||||
*/
|
||||
@NotNull
|
||||
private boolean orderable;
|
||||
|
||||
/**
|
||||
* Search value to apply to this specific column.
|
||||
*/
|
||||
@NotNull
|
||||
private Search search;
|
||||
|
||||
/**
|
||||
* Set the search value to apply to this column.
|
||||
*
|
||||
* @param searchValue if any, the search value to apply
|
||||
*/
|
||||
public void setSearchValue(final String searchValue) {
|
||||
this.search.setValue(searchValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Column{"
|
||||
+ "data='" + data + '\''
|
||||
+ ", name='" + name + '\''
|
||||
+ ", searchable=" + searchable
|
||||
+ ", orderable=" + orderable
|
||||
+ ", search=" + search
|
||||
+ '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
package hirs.attestationca.portal.datatables;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a data table input in a jQuery DataTable.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PUBLIC)
|
||||
public class DataTableInput {
|
||||
|
||||
private static final int DEFAULT_LENGTH = 10;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param draw the draw counter
|
||||
* @param start the paging start indicator
|
||||
* @param length the number of records in current draw
|
||||
* @param search the search parameter
|
||||
* @param order the orderings
|
||||
* @param columns the columns of the input
|
||||
*/
|
||||
public DataTableInput(final Integer draw, final Integer start, final Integer length,
|
||||
final Search search, final List<Order> order,
|
||||
final List<Column> columns) {
|
||||
this.draw = draw;
|
||||
this.start = start;
|
||||
this.length = length;
|
||||
this.search = search;
|
||||
this.order.addAll(order);
|
||||
this.columns.addAll(columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw counter. This is used by DataTables to ensure that the Ajax returns from server-side
|
||||
* processing requests are drawn in sequence by DataTables (Ajax requests are asynchronous and
|
||||
* thus can return out of sequence). This is used as part of the draw return parameter (see
|
||||
* below).
|
||||
*/
|
||||
@NotNull
|
||||
@Min(0)
|
||||
@Getter
|
||||
@Setter
|
||||
private int draw = 1;
|
||||
|
||||
/**
|
||||
* Paging first record indicator. This is the start point in the current data set
|
||||
* (0 index based - i.e. 0 is the first record).
|
||||
*/
|
||||
@NotNull
|
||||
@Min(0)
|
||||
@Getter
|
||||
@Setter
|
||||
private int start = 0;
|
||||
|
||||
/**
|
||||
* Number of records that the table can display in the current draw. It is expected that the
|
||||
* number of records returned will be equal to this number,
|
||||
* unless the server has fewer records to return. Note that this can be -1 to indicate that
|
||||
* all records should be returned (although that
|
||||
* negates any benefits of server-side processing!)
|
||||
*/
|
||||
@NotNull
|
||||
@Min(-1)
|
||||
@Getter
|
||||
@Setter
|
||||
private int length = DEFAULT_LENGTH;
|
||||
|
||||
/**
|
||||
* Global search parameter.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NotNull
|
||||
private Search search = new Search();
|
||||
|
||||
/**
|
||||
* Order parameter.
|
||||
*/
|
||||
@Getter
|
||||
@NotEmpty
|
||||
private List<Order> order = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Per-column search parameter.
|
||||
*/
|
||||
@Getter
|
||||
@NotEmpty
|
||||
private List<Column> columns = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Sets the orders.
|
||||
* @param order the orders
|
||||
*/
|
||||
public void setOrder(final List<Order> order) {
|
||||
this.order.clear();
|
||||
this.order.addAll(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the table columns.
|
||||
* @param columns the columns
|
||||
*/
|
||||
public void setColumns(final List<Column> columns) {
|
||||
this.columns.clear();
|
||||
this.columns.addAll(columns);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a {@link Map} of {@link Column} indexed by name
|
||||
*/
|
||||
public Map<String, Column> getColumnsAsMap() {
|
||||
Map<String, Column> map = new HashMap<String, Column>();
|
||||
for (Column column : columns) {
|
||||
map.put(column.getData(), column);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a column by its name.
|
||||
*
|
||||
* @param columnName the name of the column
|
||||
* @return the given Column, or <code>null</code> if not found
|
||||
*/
|
||||
public Column getColumn(final String columnName) {
|
||||
if (columnName == null) {
|
||||
return null;
|
||||
}
|
||||
for (Column column : columns) {
|
||||
if (columnName.equals(column.getData())) {
|
||||
return column;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new column.
|
||||
*
|
||||
* @param columnName the name of the column
|
||||
* @param searchable whether the column is searchable or not
|
||||
* @param orderable whether the column is orderable or not
|
||||
* @param searchValue if any, the search value to apply
|
||||
*/
|
||||
public void addColumn(final String columnName, final boolean searchable,
|
||||
final boolean orderable, final String searchValue) {
|
||||
this.columns.add(new Column(columnName, "", searchable, orderable,
|
||||
new Search(searchValue, false)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an order on the given column.
|
||||
*
|
||||
* @param columnName the name of the column
|
||||
* @param ascending whether the sorting is ascending or descending
|
||||
*/
|
||||
public void addOrder(final String columnName, final boolean ascending) {
|
||||
if (columnName == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
if (!columnName.equals(columns.get(i).getData())) {
|
||||
continue;
|
||||
}
|
||||
order.add(new Order(i, ascending));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the order column name, given the order ordinal value.
|
||||
* @return the order column name
|
||||
*/
|
||||
public String getOrderColumnName() {
|
||||
// attempt to get the column property based on the order index.
|
||||
String orderColumnName = "id";
|
||||
List<Order> orders = getOrder();
|
||||
if (!CollectionUtils.isEmpty(orders)) {
|
||||
int orderColumnIndex = orders.get(0).getColumn();
|
||||
|
||||
final Column column = getColumns().get(orderColumnIndex);
|
||||
|
||||
// use the column's name as the order field for hibernate if set,
|
||||
// otherwise, use the columns' data field
|
||||
if (StringUtils.isNotEmpty(column.getName())) {
|
||||
orderColumnName = column.getName();
|
||||
} else {
|
||||
orderColumnName = column.getData();
|
||||
}
|
||||
}
|
||||
return orderColumnName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a string for this object.
|
||||
* @return the string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataTableInput{"
|
||||
+ "draw=" + draw
|
||||
+ ", start=" + start
|
||||
+ ", length=" + length
|
||||
+ ", search=" + search
|
||||
+ ", order=" + order
|
||||
+ ", columns=" + columns
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package hirs.attestationca.portal.datatables;
|
||||
|
||||
import hirs.attestationca.persist.FilteredRecordsList;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -30,11 +31,11 @@ public final class DataTableResponse<T> {
|
||||
* @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());
|
||||
// }
|
||||
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
|
||||
|
@ -0,0 +1,72 @@
|
||||
package hirs.attestationca.portal.datatables;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Represents a column ordering with regards to a jQuery DataTable.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor(access = AccessLevel.PUBLIC)
|
||||
public class Order {
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param column the column index
|
||||
* @param isAscending true if ascending order
|
||||
*/
|
||||
public Order(final int column, final boolean isAscending) {
|
||||
this.column = column;
|
||||
if (isAscending) {
|
||||
this.dir = "asc";
|
||||
} else {
|
||||
this.dir = "desc";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Column to which ordering should be applied. This is an index reference
|
||||
* to the columns array of information that is also submitted to the server.
|
||||
*/
|
||||
@NotNull
|
||||
@Min(0)
|
||||
private int column;
|
||||
|
||||
/**
|
||||
* Ordering direction for this column. It will be asc or desc to indicate ascending ordering or
|
||||
* descending ordering, respectively.
|
||||
*/
|
||||
@NotNull
|
||||
@Pattern(regexp = "(desc|asc)")
|
||||
private String dir;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if ascending order, false otherwise.
|
||||
*/
|
||||
public boolean isAscending() {
|
||||
if (dir.equalsIgnoreCase("asc")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Order{"
|
||||
+ "column=" + column
|
||||
+ ", dir='" + dir + '\''
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
package hirs.attestationca.portal.datatables;
|
||||
|
||||
import hirs.attestationca.persist.CriteriaModifier;
|
||||
import hirs.attestationca.persist.FilteredRecordsList;
|
||||
import hirs.attestationca.persist.OrderedListQuerier;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A class to adapt the Javascript DataTable java class abstractions to the DBManager's getting
|
||||
* of ordered lists.
|
||||
* @param <T> The type of object to query
|
||||
*/
|
||||
public final class OrderedListQueryDataTableAdapter<T> {
|
||||
|
||||
private OrderedListQueryDataTableAdapter() {
|
||||
// do not construct
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ordered list of records using a default, no-op criteria modifier.
|
||||
* @param clazz the type of objects to query for
|
||||
* @param dbManager the db manager to execute the actual query
|
||||
* @param dataTableInput the JS DataTable query abstraction
|
||||
* @param orderColumnName the name of the column (java object field name) to query on
|
||||
* @param <T> the parameter type
|
||||
* @return the filtered record list
|
||||
*/
|
||||
public static <T> FilteredRecordsList<T> getOrderedList(final Class<? extends T> clazz,
|
||||
final OrderedListQuerier<T> dbManager,
|
||||
final DataTableInput dataTableInput,
|
||||
final String orderColumnName) {
|
||||
return getOrderedList(clazz, dbManager, dataTableInput, orderColumnName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ordered list of records.
|
||||
* @param clazz the type of objects to query for
|
||||
* @param dbManager the db manager to execute the actual query
|
||||
* @param dataTableInput the JS DataTable query abstraction
|
||||
* @param orderColumnName the name of the column (java object field name) to query on
|
||||
* @param criteriaModifier the criteria modifier
|
||||
* @param <T> the parameter type
|
||||
* @return the filtered record list
|
||||
*/
|
||||
public static <T> FilteredRecordsList<T> getOrderedList(final Class<? extends T> clazz,
|
||||
final OrderedListQuerier<T> dbManager,
|
||||
final DataTableInput dataTableInput,
|
||||
final String orderColumnName,
|
||||
final CriteriaModifier criteriaModifier) {
|
||||
|
||||
Map<String, Boolean> searchableColumnMap = new HashMap<>();
|
||||
for (Column column : dataTableInput.getColumns()) {
|
||||
searchableColumnMap.put(column.getData(), column.isSearchable());
|
||||
}
|
||||
|
||||
List<Order> orders = dataTableInput.getOrder();
|
||||
boolean isAscending = true;
|
||||
if (!CollectionUtils.isEmpty(orders)) {
|
||||
isAscending = orders.get(0).isAscending();
|
||||
}
|
||||
|
||||
return dbManager.getOrderedList(clazz, orderColumnName, isAscending,
|
||||
dataTableInput.getStart(), dataTableInput.getLength(),
|
||||
dataTableInput.getSearch().getValue(),
|
||||
searchableColumnMap, criteriaModifier);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package hirs.attestationca.portal.datatables;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Represents a jQuery DataTables search parameter.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor(access = AccessLevel.PUBLIC)
|
||||
public class Search {
|
||||
|
||||
/**
|
||||
* Constructor for a non-regex search.
|
||||
* @param value the search value
|
||||
*/
|
||||
public Search(final String value) {
|
||||
this(value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Global search value. To be applied to all columns which have searchable as true.
|
||||
*/
|
||||
@NotNull
|
||||
private String value = "";
|
||||
|
||||
/**
|
||||
* true if the global filter should be treated as a regular expression for advanced searching,
|
||||
* false otherwise. Note that normally server-side processing scripts will not perform regular
|
||||
* expression searching for performance reasons on large data sets,
|
||||
* but it is technically possible and at the discretion of your script.
|
||||
*/
|
||||
@NotNull
|
||||
private boolean regex;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Search{"
|
||||
+ "value='" + value + '\''
|
||||
+ ", regex=" + regex
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,47 @@
|
||||
package hirs.attestationca.portal.page.controllers;
|
||||
|
||||
import hirs.attestationca.persist.DBServiceException;
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
|
||||
import hirs.attestationca.persist.service.CertificateService;
|
||||
import hirs.attestationca.persist.service.CertificateServiceImpl;
|
||||
import hirs.attestationca.portal.page.Page;
|
||||
import hirs.attestationca.portal.page.PageController;
|
||||
import hirs.attestationca.portal.page.PageMessages;
|
||||
import hirs.attestationca.portal.page.params.NoPageParams;
|
||||
import hirs.attestationca.portal.page.utils.CertificateStringMapBuilder;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.bouncycastle.util.encoders.DecoderException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
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.security.cert.CertificateEncodingException;
|
||||
//import java.security.cert.X509Certificate;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
// note uploading base64 certs, old or new having decode issues check ACA channel
|
||||
|
||||
@Log4j2
|
||||
@Controller
|
||||
@ -34,12 +65,12 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
||||
* 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
|
||||
// * @param crudManager the CRUD manager for certificates
|
||||
// * @param acaCertificate the ACA's X509 certificate
|
||||
*/
|
||||
@Autowired
|
||||
public CertificatePageController(
|
||||
final CertificateServiceImpl certificateServiceImpl
|
||||
final CertificateServiceImpl certificateServiceImpl//,
|
||||
// final CrudManager<Certificate> crudManager,
|
||||
// final X509Certificate acaCertificate
|
||||
) {
|
||||
@ -48,12 +79,12 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
||||
// 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);
|
||||
// certificateAuthorityCredential
|
||||
// = new CertificateAuthorityCredential(acaCertificate.getEncoded());
|
||||
// } catch (IOException ioEx) {
|
||||
// log.error("Failed to read ACA certificate", ioEx);
|
||||
// } catch (CertificateEncodingException ceEx) {
|
||||
// log.error("Error getting encoded ACA certificate", ceEx);
|
||||
// }
|
||||
}
|
||||
|
||||
@ -70,4 +101,524 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
||||
public ModelAndView initPage(final NoPageParams params, final Model model) {
|
||||
return getBaseModelAndView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path for the view and the data model for the page.
|
||||
*
|
||||
* @param certificateType String containing the certificate type
|
||||
* @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("/{certificateType}")
|
||||
public ModelAndView initPage(@PathVariable("certificateType") final String certificateType,
|
||||
final NoPageParams params, final Model model) {
|
||||
|
||||
ModelAndView mav = null;
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
// add page information
|
||||
switch (certificateType) {
|
||||
case PLATFORMCREDENTIAL:
|
||||
mav = getBaseModelAndView(Page.PLATFORM_CREDENTIALS);
|
||||
break;
|
||||
case ENDORSEMENTCREDENTIAL:
|
||||
mav = getBaseModelAndView(Page.ENDORSEMENT_KEY_CREDENTIALS);
|
||||
break;
|
||||
case ISSUEDCERTIFICATES:
|
||||
mav = getBaseModelAndView(Page.ISSUED_CERTIFICATES);
|
||||
break;
|
||||
case TRUSTCHAIN:
|
||||
mav = getBaseModelAndView(Page.TRUST_CHAIN);
|
||||
// Map with the ACA certificate information
|
||||
data.putAll(CertificateStringMapBuilder.getCertificateAuthorityInformation(
|
||||
certificateAuthorityCredential, this.certificateServiceImpl));
|
||||
mav.addObject(ACA_CERT_DATA, data);
|
||||
break;
|
||||
default:
|
||||
// send to an error page
|
||||
break;
|
||||
}
|
||||
|
||||
return mav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload and processes a credential.
|
||||
*
|
||||
* @param certificateType String containing the certificate type
|
||||
* @param files the files to process
|
||||
* @param attr the redirection attributes
|
||||
* @return the redirection view
|
||||
* @throws URISyntaxException if malformed URI
|
||||
*/
|
||||
@RequestMapping(value = "/{certificateType}/upload", method = RequestMethod.POST)
|
||||
protected RedirectView upload(
|
||||
@PathVariable("certificateType") final String certificateType,
|
||||
@RequestParam("file") final MultipartFile[] files,
|
||||
final RedirectAttributes attr) throws URISyntaxException {
|
||||
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
PageMessages messages = new PageMessages();
|
||||
|
||||
for (MultipartFile file : files) {
|
||||
//Parse certificate
|
||||
Certificate certificate = parseCertificate(certificateType, file, messages);
|
||||
|
||||
//Store only if it was parsed
|
||||
if (certificate != null) {
|
||||
storeCertificate(
|
||||
certificateType,
|
||||
file.getOriginalFilename(),
|
||||
messages, certificate,
|
||||
certificateServiceImpl);
|
||||
}
|
||||
}
|
||||
|
||||
//Add messages to the model
|
||||
model.put(MESSAGES_ATTRIBUTE, messages);
|
||||
|
||||
return redirectTo(getCertificatePage(certificateType), new NoPageParams(), model, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles request to download the ACA cert by writing it to the response
|
||||
* stream for download.
|
||||
*
|
||||
* @param response the response object (needed to update the header with the
|
||||
* file name)
|
||||
*
|
||||
* @throws java.io.IOException when writing to response output stream
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/trust-chain/download-aca-cert", method = RequestMethod.GET)
|
||||
public void downloadAcaCertificate(final HttpServletResponse response)
|
||||
throws IOException {
|
||||
|
||||
// Set filename for download.
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"hirs-aca-cert.cer\"");
|
||||
response.setContentType("application/octet-stream");
|
||||
|
||||
// write cert to output stream
|
||||
response.getOutputStream().write(certificateAuthorityCredential.getRawBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles request to download the certs by writing it to the response stream
|
||||
* for download in bulk.
|
||||
*
|
||||
* @param response the response object (needed to update the header with the
|
||||
* file name)
|
||||
* @throws java.io.IOException when writing to response output stream
|
||||
*/
|
||||
@RequestMapping(value = "/trust-chain/bulk", method = RequestMethod.GET)
|
||||
public void caBulkDownload(final HttpServletResponse response)
|
||||
throws IOException {
|
||||
log.info("Handling request to download all trust chain certificates");
|
||||
String fileName = "trust-chain.zip";
|
||||
final String singleFileName = "ca-certificates";
|
||||
|
||||
// Set filename for download.
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
|
||||
response.setContentType("application/zip");
|
||||
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
|
||||
// get all files
|
||||
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(CertificateAuthorityCredential.class), singleFileName);
|
||||
// write cert to output stream
|
||||
} catch (IllegalArgumentException ex) {
|
||||
String uuidError = "Failed to parse ID from: ";
|
||||
log.error(uuidError, ex);
|
||||
// send a 404 error when invalid certificate
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles request to download the certs by writing it to the response stream
|
||||
* for download in bulk.
|
||||
*
|
||||
* @param response the response object (needed to update the header with the
|
||||
* file name)
|
||||
* @throws java.io.IOException when writing to response output stream
|
||||
*/
|
||||
@RequestMapping(value = "/platform-credentials/bulk", method = RequestMethod.GET)
|
||||
public void pcBulkDownload(final HttpServletResponse response)
|
||||
throws IOException {
|
||||
log.info("Handling request to download all platform certificates");
|
||||
String fileName = "platform_certificates.zip";
|
||||
final String singleFileName = "Platform_Certificate";
|
||||
String zipFileName;
|
||||
|
||||
// Set filename for download.
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
|
||||
response.setContentType("application/zip");
|
||||
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
|
||||
// get all files
|
||||
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(PlatformCredential.class), singleFileName);
|
||||
// write cert to output stream
|
||||
} catch (IllegalArgumentException ex) {
|
||||
String uuidError = "Failed to parse ID from: ";
|
||||
log.error(uuidError, ex);
|
||||
// send a 404 error when invalid certificate
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles request to download the certs by writing it to the response stream
|
||||
* for download in bulk.
|
||||
*
|
||||
* @param response the response object (needed to update the header with the
|
||||
* file name)
|
||||
* @throws java.io.IOException when writing to response output stream
|
||||
*/
|
||||
@RequestMapping(value = "/issued-certificates/bulk", method = RequestMethod.GET)
|
||||
public void icBulkDownload(final HttpServletResponse response)
|
||||
throws IOException {
|
||||
log.info("Handling request to download all issued certificates");
|
||||
String fileName = "issued_certificates.zip";
|
||||
final String singleFileName = "Issued_Certificate";
|
||||
String zipFileName;
|
||||
|
||||
// Set filename for download.
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
|
||||
response.setContentType("application/zip");
|
||||
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
|
||||
// get all files
|
||||
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(IssuedAttestationCertificate.class), singleFileName);
|
||||
// write cert to output stream
|
||||
} catch (IllegalArgumentException ex) {
|
||||
String uuidError = "Failed to parse ID from: ";
|
||||
log.error(uuidError, ex);
|
||||
// send a 404 error when invalid certificate
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles request to download the certs by writing it to the response stream
|
||||
* for download in bulk.
|
||||
*
|
||||
* @param response the response object (needed to update the header with the
|
||||
* file name)
|
||||
* @throws java.io.IOException when writing to response output stream
|
||||
*/
|
||||
@RequestMapping(value = "/endorsement-key-credentials/bulk", method = RequestMethod.GET)
|
||||
public void ekBulkDownload(final HttpServletResponse response)
|
||||
throws IOException {
|
||||
log.info("Handling request to download all endorsement certificates");
|
||||
String fileName = "endorsement_certificates.zip";
|
||||
final String singleFileName = "Endorsement_Certificates";
|
||||
|
||||
// Set filename for download.
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
|
||||
response.setContentType("application/zip");
|
||||
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
|
||||
// get all files
|
||||
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(EndorsementCredential.class), singleFileName);
|
||||
// write cert to output stream
|
||||
} catch (IllegalArgumentException ex) {
|
||||
String uuidError = "Failed to parse ID from: ";
|
||||
log.error(uuidError, ex);
|
||||
// send a 404 error when invalid certificate
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
private ZipOutputStream bulkDownload(final ZipOutputStream zipOut,
|
||||
final List<Certificate> certificates,
|
||||
final String singleFileName) throws IOException {
|
||||
String zipFileName;
|
||||
// get all files
|
||||
for (Certificate certificate : certificates) {
|
||||
zipFileName = String.format("%s[%s].cer", singleFileName,
|
||||
Integer.toHexString(certificate.getCertificateHash()));
|
||||
// configure the zip entry, the properties of the 'file'
|
||||
ZipEntry zipEntry = new ZipEntry(zipFileName);
|
||||
zipEntry.setSize((long) certificate.getRawBytes().length * Byte.SIZE);
|
||||
zipEntry.setTime(System.currentTimeMillis());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
// the content of the resource
|
||||
StreamUtils.copy(certificate.getRawBytes(), zipOut);
|
||||
zipOut.closeEntry();
|
||||
}
|
||||
zipOut.finish();
|
||||
return zipOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the page based on the certificate type.
|
||||
*
|
||||
* @param certificateType String containing the certificate type
|
||||
* @return the page for the certificate type.
|
||||
*/
|
||||
private static Page getCertificatePage(final String certificateType) {
|
||||
// get page information (default to TRUST_CHAIN)
|
||||
return switch (certificateType) {
|
||||
case PLATFORMCREDENTIAL -> Page.PLATFORM_CREDENTIALS;
|
||||
case ENDORSEMENTCREDENTIAL -> Page.ENDORSEMENT_KEY_CREDENTIALS;
|
||||
case ISSUEDCERTIFICATES -> Page.ISSUED_CERTIFICATES;
|
||||
default -> Page.TRUST_CHAIN;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the certificate by the hash code of its bytes. Looks for both
|
||||
* archived and unarchived certificates.
|
||||
*
|
||||
* @param certificateType String containing the certificate type
|
||||
* @param certificateHash the hash of the certificate's bytes
|
||||
* @param certificateManager the certificate manager to query
|
||||
* @return the certificate or null if none is found
|
||||
*/
|
||||
private Certificate getCertificateByHash(
|
||||
final String certificateType,
|
||||
final int certificateHash,
|
||||
final CertificateService certificateManager) {
|
||||
|
||||
switch (certificateType) {
|
||||
case PLATFORMCREDENTIAL:
|
||||
return PlatformCredential
|
||||
.select(certificateManager)
|
||||
.includeArchived()
|
||||
.byHashCode(certificateHash)
|
||||
.getCertificate();
|
||||
case ENDORSEMENTCREDENTIAL:
|
||||
// return EndorsementCredential
|
||||
// .select(certificateManager)
|
||||
// .includeArchived()
|
||||
// .byHashCode(certificateHash)
|
||||
// .getCertificate();
|
||||
case TRUSTCHAIN:
|
||||
return CertificateAuthorityCredential
|
||||
.select(certificateManager)
|
||||
.includeArchived()
|
||||
.byHashCode(certificateHash)
|
||||
.getCertificate();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the certificate by the platform serial number.
|
||||
*
|
||||
* @param certificateType String containing the certificate type
|
||||
* @param serialNumber the platform serial number
|
||||
* @param certificateManager the certificate manager to query
|
||||
* @return the certificate or null if none is found
|
||||
*/
|
||||
private List<PlatformCredential> getCertificateByBoardSN(
|
||||
final String certificateType,
|
||||
final String serialNumber,
|
||||
final CertificateService certificateManager) {
|
||||
|
||||
if (serialNumber == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (certificateType) {
|
||||
case PLATFORMCREDENTIAL:
|
||||
return PlatformCredential
|
||||
.select(certificateManager)
|
||||
.byBoardSerialNumber(serialNumber)
|
||||
.getCertificates().stream().collect(Collectors.toList());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an uploaded file into a certificate and populates the given model
|
||||
* with error messages if parsing fails.
|
||||
*
|
||||
* @param certificateType String containing the certificate type
|
||||
* @param file the file being uploaded from the portal
|
||||
* @param messages contains any messages that will be display on the page
|
||||
* @return the parsed certificate or null if parsing failed.
|
||||
*/
|
||||
private Certificate parseCertificate(
|
||||
final String certificateType,
|
||||
final MultipartFile file,
|
||||
final PageMessages messages) {
|
||||
log.info("Received File of Size: " + file.getSize());
|
||||
|
||||
byte[] fileBytes;
|
||||
String fileName = file.getOriginalFilename();
|
||||
|
||||
// build the certificate from the uploaded bytes
|
||||
try {
|
||||
fileBytes = file.getBytes();
|
||||
} catch (IOException e) {
|
||||
final String failMessage = String.format(
|
||||
"Failed to read uploaded file (%s): ", fileName);
|
||||
log.error(failMessage, e);
|
||||
messages.addError(failMessage + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
switch (certificateType) {
|
||||
case PLATFORMCREDENTIAL:
|
||||
return new PlatformCredential(fileBytes);
|
||||
case ENDORSEMENTCREDENTIAL:
|
||||
return new EndorsementCredential(fileBytes);
|
||||
case TRUSTCHAIN:
|
||||
return new CertificateAuthorityCredential(fileBytes);
|
||||
default:
|
||||
final String failMessage = String.format("Failed to parse uploaded file "
|
||||
+ "(%s). Invalid certificate type: %s", fileName, certificateType);
|
||||
log.error(failMessage);
|
||||
messages.addError(failMessage);
|
||||
return null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
final String failMessage = String.format(
|
||||
"Failed to parse uploaded file (%s): ", fileName);
|
||||
log.error(failMessage, e);
|
||||
messages.addError(failMessage + e.getMessage());
|
||||
return null;
|
||||
} catch (DecoderException dEx) {
|
||||
final String failMessage = String.format(
|
||||
"Failed to parse uploaded pem file (%s): ", fileName);
|
||||
log.error(failMessage, dEx);
|
||||
messages.addError(failMessage + dEx.getMessage());
|
||||
return null;
|
||||
} catch (IllegalArgumentException e) {
|
||||
final String failMessage = String.format(
|
||||
"Certificate format not recognized(%s): ", fileName);
|
||||
log.error(failMessage, e);
|
||||
messages.addError(failMessage + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the given certificate in the database.
|
||||
*
|
||||
* @param certificateType String containing the certificate type
|
||||
* @param fileName contain the name of the file of the certificate to
|
||||
* be stored
|
||||
* @param messages contains any messages that will be display on the page
|
||||
* @param certificate the certificate to store
|
||||
* @param certificateManager the DB manager to use
|
||||
* @return the messages for the page
|
||||
*/
|
||||
private void storeCertificate(
|
||||
final String certificateType,
|
||||
final String fileName,
|
||||
final PageMessages messages,
|
||||
final Certificate certificate,
|
||||
final CertificateService certificateManager) {
|
||||
|
||||
Certificate existingCertificate;
|
||||
|
||||
// look for an identical certificate in the database
|
||||
try {
|
||||
existingCertificate = getCertificateByHash(
|
||||
certificateType,
|
||||
certificate.getCertificateHash(),
|
||||
certificateManager);
|
||||
} catch (DBServiceException e) {
|
||||
final String failMessage = "Querying for existing certificate failed ("
|
||||
+ fileName + "): ";
|
||||
messages.addError(failMessage + e.getMessage());
|
||||
log.error(failMessage, e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// save the new certificate if no match is found
|
||||
if (existingCertificate == null) {
|
||||
if (certificateType.equals(PLATFORMCREDENTIAL)) {
|
||||
PlatformCredential platformCertificate = (PlatformCredential) certificate;
|
||||
if (platformCertificate.isPlatformBase()) {
|
||||
List<PlatformCredential> sharedCertificates = getCertificateByBoardSN(
|
||||
certificateType,
|
||||
platformCertificate.getPlatformSerial(),
|
||||
certificateManager);
|
||||
|
||||
if (sharedCertificates != null) {
|
||||
for (PlatformCredential pc : sharedCertificates) {
|
||||
if (pc.isPlatformBase()) {
|
||||
final String failMessage = "Storing certificate failed: "
|
||||
+ "platform credential "
|
||||
+ "chain (" + pc.getPlatformSerial()
|
||||
+ ") base already exists in this chain ("
|
||||
+ fileName + ")";
|
||||
messages.addError(failMessage);
|
||||
log.error(failMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /**else {
|
||||
// this is a delta, check if the holder exists.
|
||||
PlatformCredential holderPC = PlatformCredential
|
||||
.select(certificateManager)
|
||||
.bySerialNumber(platformCertificate.getHolderSerialNumber())
|
||||
.getCertificate();
|
||||
if (holderPC == null) {
|
||||
final String failMessage = "Storing certificate failed: "
|
||||
+ "delta credential"
|
||||
+ " must have an existing holder stored. "
|
||||
+ "Credential serial "
|
||||
+ platformCertificate.getHolderSerialNumber()
|
||||
+ " doesn't exist.";
|
||||
messages.addError(failMessage);
|
||||
LOGGER.error(failMessage);
|
||||
return;
|
||||
}
|
||||
}**/
|
||||
}
|
||||
|
||||
certificateManager.saveCertificate(certificate);
|
||||
|
||||
final String successMsg
|
||||
= String.format("New certificate successfully uploaded (%s): ", fileName);
|
||||
messages.addSuccess(successMsg);
|
||||
log.info(successMsg);
|
||||
return;
|
||||
}
|
||||
} catch (DBServiceException e) {
|
||||
final String failMessage = String.format("Storing new certificate failed (%s): ",
|
||||
fileName);
|
||||
messages.addError(failMessage + e.getMessage());
|
||||
log.error(failMessage, e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// if an identical certificate is archived, update the existing certificate to
|
||||
// unarchive it and change the creation date
|
||||
if (existingCertificate.isArchived()) {
|
||||
existingCertificate.restore();
|
||||
existingCertificate.resetCreateTime();
|
||||
certificateManager.updateCertificate(existingCertificate);
|
||||
|
||||
final String successMsg = String.format("Pre-existing certificate "
|
||||
+ "found and unarchived (%s): ", fileName);
|
||||
messages.addSuccess(successMsg);
|
||||
log.info(successMsg);
|
||||
return;
|
||||
}
|
||||
} catch (DBServiceException e) {
|
||||
final String failMessage = String.format("Found an identical"
|
||||
+ " pre-existing certificate in the "
|
||||
+ "archive, but failed to unarchive it (%s): ", fileName);
|
||||
messages.addError(failMessage + e.getMessage());
|
||||
log.error(failMessage, e);
|
||||
return;
|
||||
}
|
||||
|
||||
// if an identical certificate is already unarchived, do nothing and show a fail message
|
||||
final String failMessage
|
||||
= String.format("Storing certificate failed: an identical"
|
||||
+ " certificate already exists (%s): ", fileName);
|
||||
messages.addError(failMessage);
|
||||
log.error(failMessage);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,601 @@
|
||||
package hirs.attestationca.portal.page.controllers;
|
||||
|
||||
import hirs.attestationca.persist.DBServiceException;
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
|
||||
import hirs.attestationca.persist.service.CertificateService;
|
||||
import hirs.attestationca.persist.service.ReferenceDigestValueService;
|
||||
import hirs.attestationca.persist.service.ReferenceDigestValueServiceImpl;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestService;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
|
||||
import hirs.attestationca.persist.service.SupplyChainValidationServiceImpl;
|
||||
import hirs.attestationca.persist.validation.ReferenceManifestValidator;
|
||||
import hirs.attestationca.persist.validation.SupplyChainValidatorException;
|
||||
import hirs.attestationca.portal.page.Page;
|
||||
import hirs.attestationca.portal.page.PageController;
|
||||
import hirs.attestationca.portal.page.PageMessages;
|
||||
import hirs.attestationca.portal.page.params.ReferenceManifestDetailsPageParams;
|
||||
import hirs.attestationca.portal.page.utils.SupplyChainCredentialValidator;
|
||||
import hirs.utils.SwidResource;
|
||||
import hirs.utils.tpm.eventlog.TCGEventLog;
|
||||
import hirs.utils.tpm.eventlog.TpmPcrEvent;
|
||||
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.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Controller for the Reference Manifest Details page.
|
||||
*/
|
||||
@Log4j2
|
||||
@Controller
|
||||
@RequestMapping("/rim-details")
|
||||
public class ReferenceManifestDetailsPageController extends PageController<ReferenceManifestDetailsPageParams> {
|
||||
|
||||
private final ReferenceManifestService referenceManifestManager;
|
||||
private final ReferenceDigestValueService referenceEventManager;
|
||||
private final CertificateService certificateService;
|
||||
private static final ReferenceManifestValidator RIM_VALIDATOR
|
||||
= new ReferenceManifestValidator();
|
||||
|
||||
/**
|
||||
* Constructor providing the Page's display and routing specification.
|
||||
*
|
||||
* @param referenceManifestManager the reference manifest manager.
|
||||
* @param referenceEventManager the reference event manager.
|
||||
* @param certificateService the certificate manager.
|
||||
*/
|
||||
@Autowired
|
||||
public ReferenceManifestDetailsPageController(
|
||||
final ReferenceManifestServiceImpl referenceManifestManager,
|
||||
final ReferenceDigestValueServiceImpl referenceEventManager,
|
||||
final CertificateService certificateService) {
|
||||
super(Page.RIM_DETAILS);
|
||||
this.referenceManifestManager = referenceManifestManager;
|
||||
this.referenceEventManager = referenceEventManager;
|
||||
this.certificateService = certificateService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filePath 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
|
||||
public ModelAndView initPage(final ReferenceManifestDetailsPageParams params,
|
||||
final Model model) {
|
||||
// get the basic information to render the page
|
||||
ModelAndView mav = getBaseModelAndView();
|
||||
PageMessages messages = new PageMessages();
|
||||
|
||||
// Map with the rim 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.debug(typeError);
|
||||
mav.addObject(MESSAGES_ATTRIBUTE, messages);
|
||||
} else {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(params.getId());
|
||||
data.putAll(getRimDetailInfo(uuid, referenceManifestManager,
|
||||
referenceEventManager, certificateService));
|
||||
} catch (IllegalArgumentException iaEx) {
|
||||
String uuidError = "Failed to parse ID from: " + params.getId();
|
||||
messages.addError(uuidError);
|
||||
log.error(uuidError, iaEx);
|
||||
} catch (Exception ioEx) {
|
||||
log.error(ioEx);
|
||||
}
|
||||
if (data.isEmpty()) {
|
||||
String notFoundMessage = "Unable to find RIM 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes the place of an entire class for a string builder.
|
||||
* Gathers all information and returns it for displays.
|
||||
*
|
||||
* @param uuid database reference for the requested RIM.
|
||||
* @param referenceManifestManager the reference manifest manager.
|
||||
* @param referenceEventManager the reference event manager.
|
||||
* @param certificateManager the certificate manager.
|
||||
* @return mapping of the RIM information from the database.
|
||||
* @throws java.io.IOException error for reading file bytes.
|
||||
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
|
||||
* @throws CertificateException if a certificate doesn't parse.
|
||||
*/
|
||||
public static HashMap<String, Object> getRimDetailInfo(final UUID uuid,
|
||||
final ReferenceManifestService referenceManifestManager,
|
||||
final ReferenceDigestValueService referenceEventManager,
|
||||
final CertificateService certificateManager)
|
||||
throws IOException,
|
||||
CertificateException, NoSuchAlgorithmException {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
|
||||
BaseReferenceManifest bRim = BaseReferenceManifest.select(referenceManifestManager)
|
||||
.byEntityId(uuid).getRIM();
|
||||
|
||||
if (bRim != null) {
|
||||
data.putAll(getBaseRimInfo(bRim, referenceManifestManager, certificateManager));
|
||||
}
|
||||
|
||||
SupportReferenceManifest sRim = SupportReferenceManifest.select(referenceManifestManager)
|
||||
.byEntityId(uuid).getRIM();
|
||||
|
||||
if (sRim != null) {
|
||||
data.putAll(getSupportRimInfo(sRim, referenceManifestManager));
|
||||
}
|
||||
|
||||
EventLogMeasurements bios = EventLogMeasurements.select(referenceManifestManager)
|
||||
.byEntityId(uuid).getRIM();
|
||||
|
||||
if (bios != null) {
|
||||
data.putAll(getMeasurementsRimInfo(bios, referenceManifestManager,
|
||||
referenceEventManager));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes the place of an entire class for a string builder.
|
||||
* Gathers all information and returns it for displays.
|
||||
*
|
||||
* @param baseRim established ReferenceManifest Type.
|
||||
* @param referenceManifestManager the reference manifest manager.
|
||||
* @param certificateManager the certificate manager.
|
||||
* @return mapping of the RIM information from the database.
|
||||
* @throws java.io.IOException error for reading file bytes.
|
||||
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
|
||||
* @throws CertificateException if a certificate doesn't parse.
|
||||
*/
|
||||
private static HashMap<String, Object> getBaseRimInfo(
|
||||
final BaseReferenceManifest baseRim,
|
||||
final ReferenceManifestService referenceManifestManager,
|
||||
final CertificateService certificateManager)
|
||||
throws IOException, CertificateException, NoSuchAlgorithmException {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
|
||||
// Software Identity
|
||||
data.put("swidName", baseRim.getSwidName());
|
||||
data.put("swidVersion", baseRim.getSwidVersion());
|
||||
data.put("swidTagVersion", baseRim.getSwidTagVersion());
|
||||
if (baseRim.getSwidCorpus() == 1) {
|
||||
data.put("swidCorpus", "True");
|
||||
} else {
|
||||
data.put("swidCorpus", "False");
|
||||
}
|
||||
if (baseRim.isSwidPatch()) {
|
||||
data.put("swidPatch", "True");
|
||||
} else {
|
||||
data.put("swidPatch", "False");
|
||||
}
|
||||
if (baseRim.isSwidSupplemental()) {
|
||||
data.put("swidSupplemental", "True");
|
||||
} else {
|
||||
data.put("swidSupplemental", "False");
|
||||
}
|
||||
data.put("swidTagId", baseRim.getTagId());
|
||||
// Entity
|
||||
data.put("entityName", baseRim.getEntityName());
|
||||
data.put("entityRegId", baseRim.getEntityRegId());
|
||||
data.put("entityRole", baseRim.getEntityRole());
|
||||
data.put("entityThumbprint", baseRim.getEntityThumbprint());
|
||||
// Link
|
||||
data.put("linkHref", baseRim.getLinkHref());
|
||||
data.put("linkHrefLink", "");
|
||||
for (BaseReferenceManifest bRim : BaseReferenceManifest
|
||||
.select(referenceManifestManager).getRIMs()) {
|
||||
if (baseRim.getLinkHref().contains(bRim.getTagId())) {
|
||||
data.put("linkHrefLink", bRim.getId());
|
||||
}
|
||||
}
|
||||
data.put("linkRel", baseRim.getLinkRel());
|
||||
data.put("platformManufacturer", baseRim.getPlatformManufacturer());
|
||||
data.put("platformManufacturerId", baseRim.getPlatformManufacturerId());
|
||||
data.put("platformModel", baseRim.getPlatformModel());
|
||||
data.put("platformVersion", baseRim.getPlatformVersion());
|
||||
data.put("payloadType", baseRim.getPayloadType());
|
||||
data.put("colloquialVersion", baseRim.getColloquialVersion());
|
||||
data.put("edition", baseRim.getEdition());
|
||||
data.put("product", baseRim.getProduct());
|
||||
data.put("revision", baseRim.getRevision());
|
||||
data.put("bindingSpec", baseRim.getBindingSpec());
|
||||
data.put("bindingSpecVersion", baseRim.getBindingSpecVersion());
|
||||
data.put("pcUriGlobal", baseRim.getPcURIGlobal());
|
||||
data.put("pcUriLocal", baseRim.getPcURILocal());
|
||||
data.put("rimLinkHash", baseRim.getRimLinkHash());
|
||||
if (baseRim.getRimLinkHash() != null) {
|
||||
ReferenceManifest rim = BaseReferenceManifest.select(referenceManifestManager)
|
||||
.byHexDecHash(baseRim.getRimLinkHash()).getRIM();
|
||||
if (rim != null) {
|
||||
data.put("rimLinkId", rim.getId());
|
||||
data.put("linkHashValid", true);
|
||||
} else {
|
||||
data.put("linkHashValid", false);
|
||||
}
|
||||
}
|
||||
data.put("rimType", baseRim.getRimType());
|
||||
|
||||
List<SwidResource> resources = baseRim.parseResource();
|
||||
TCGEventLog logProcessor = null;
|
||||
SupportReferenceManifest support = null;
|
||||
|
||||
if (baseRim.getAssociatedRim() == null) {
|
||||
support = SupportReferenceManifest.select(referenceManifestManager)
|
||||
.byManufacturer(baseRim.getPlatformManufacturer())
|
||||
.getRIM();
|
||||
if (support != null) {
|
||||
baseRim.setAssociatedRim(support.getId());
|
||||
}
|
||||
} else {
|
||||
support = SupportReferenceManifest.select(referenceManifestManager)
|
||||
.byEntityId(baseRim.getAssociatedRim()).getRIM();
|
||||
}
|
||||
// going to have to pull the filename and grab that from the DB
|
||||
// to get the id to make the link
|
||||
RIM_VALIDATOR.setRim(baseRim);
|
||||
for (SwidResource swidRes : resources) {
|
||||
if (support != null && swidRes.getHashValue()
|
||||
.equalsIgnoreCase(support.getHexDecHash())) {
|
||||
RIM_VALIDATOR.validateSupportRimHash(support.getRimBytes(),
|
||||
swidRes.getHashValue());
|
||||
if (RIM_VALIDATOR.isSupportRimValid()) {
|
||||
data.put("supportRimHashValid", true);
|
||||
} else {
|
||||
data.put("supportRimHashValid", false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data.put("associatedRim", baseRim.getAssociatedRim());
|
||||
data.put("swidFiles", resources);
|
||||
if (support != null && (!baseRim.isSwidSupplemental()
|
||||
&& !baseRim.isSwidPatch())) {
|
||||
data.put("pcrList", support.getExpectedPCRList());
|
||||
}
|
||||
|
||||
Set<CertificateAuthorityCredential> certificates =
|
||||
CertificateAuthorityCredential.select(certificateManager)
|
||||
.getCertificates();
|
||||
//Report invalid signature unless RIM_VALIDATOR validates it and cert path is valid
|
||||
data.put("signatureValid", false);
|
||||
for (CertificateAuthorityCredential cert : certificates) {
|
||||
SupplyChainValidationServiceImpl scvsImpl =
|
||||
new SupplyChainValidationServiceImpl(certificateManager);
|
||||
KeyStore keystore = scvsImpl.getCaChain(cert);
|
||||
if (RIM_VALIDATOR.validateXmlSignature(cert)) {
|
||||
try {
|
||||
if (SupplyChainCredentialValidator.verifyCertificate(
|
||||
cert.getX509Certificate(), keystore)) {
|
||||
data.replace("signatureValid", true);
|
||||
break;
|
||||
}
|
||||
} catch (SupplyChainValidatorException e) {
|
||||
log.error("Error verifying cert chain: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
data.put("skID", RIM_VALIDATOR.getSubjectKeyIdentifier());
|
||||
try {
|
||||
for (CertificateAuthorityCredential cert : certificates) {
|
||||
if (Arrays.equals(cert.getEncodedPublicKey(),
|
||||
RIM_VALIDATOR.getPublicKey().getEncoded())) {
|
||||
data.put("issuerID", cert.getId().toString());
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
log.error("Unable to link signing certificate: " + e.getMessage());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes the place of an entire class for a string builder.
|
||||
* Gathers all information and returns it for displays.
|
||||
*
|
||||
* @param support established ReferenceManifest Type.
|
||||
* @param referenceManifestManager the reference manifest manager.
|
||||
* @return mapping of the RIM information from the database.
|
||||
* @throws java.io.IOException error for reading file bytes.
|
||||
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
|
||||
* @throws CertificateException if a certificate doesn't parse.
|
||||
*/
|
||||
private static HashMap<String, Object> getSupportRimInfo(
|
||||
final SupportReferenceManifest support,
|
||||
final ReferenceManifestService referenceManifestManager)
|
||||
throws IOException, CertificateException, NoSuchAlgorithmException {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
EventLogMeasurements measurements = null;
|
||||
|
||||
if (support.getAssociatedRim() == null) {
|
||||
Set<BaseReferenceManifest> baseRims = BaseReferenceManifest
|
||||
.select(referenceManifestManager)
|
||||
.byRimType(ReferenceManifest.BASE_RIM).getRIMs();
|
||||
for (BaseReferenceManifest baseRim : baseRims) {
|
||||
if (baseRim != null && baseRim.getAssociatedRim() != null
|
||||
&& baseRim.getAssociatedRim().equals(support.getId())) {
|
||||
support.setAssociatedRim(baseRim.getId());
|
||||
try {
|
||||
referenceManifestManager.updateReferenceManifest(support, support.getId());
|
||||
} catch (DBServiceException ex) {
|
||||
log.error("Failed to update Support RIM", ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testing this independent of the above if statement because the above
|
||||
// starts off checking if associated rim is null; that is irrelevant for
|
||||
// this statement.
|
||||
measurements = EventLogMeasurements.select(referenceManifestManager)
|
||||
.byHexDecHash(support.getHexDecHash()).getRIM();
|
||||
|
||||
if (support.isSwidPatch()) {
|
||||
data.put("swidPatch", "True");
|
||||
} else {
|
||||
data.put("swidPatch", "False");
|
||||
}
|
||||
if (support.isSwidSupplemental()) {
|
||||
data.put("swidSupplemental", "True");
|
||||
} else {
|
||||
data.put("swidSupplemental", "False");
|
||||
}
|
||||
data.put("swidBase", (!support.isSwidPatch()
|
||||
&& !support.isSwidSupplemental()));
|
||||
data.put("baseRim", support.getTagId());
|
||||
data.put("associatedRim", support.getAssociatedRim());
|
||||
data.put("rimType", support.getRimType());
|
||||
data.put("tagId", support.getTagId());
|
||||
|
||||
TCGEventLog logProcessor = new TCGEventLog(support.getRimBytes());
|
||||
LinkedList<TpmPcrEvent> tpmPcrEvents = new LinkedList<>();
|
||||
TCGEventLog measurementsProcess;
|
||||
if (measurements != null) {
|
||||
measurementsProcess = new TCGEventLog((measurements.getRimBytes()));
|
||||
HashMap<String, TpmPcrEvent> digestMap = new HashMap<>();
|
||||
for (TpmPcrEvent tpe : logProcessor.getEventList()) {
|
||||
digestMap.put(tpe.getEventDigestStr(), tpe);
|
||||
if (!support.isSwidSupplemental()
|
||||
&& !tpe.eventCompare(
|
||||
measurementsProcess.getEventByNumber(
|
||||
tpe.getEventNumber()))) {
|
||||
tpe.setError(true);
|
||||
}
|
||||
tpmPcrEvents.add(tpe);
|
||||
}
|
||||
for (TpmPcrEvent tpe : logProcessor.getEventList()) {
|
||||
tpe.setError(!digestMap.containsKey(tpe.getEventDigestStr()));
|
||||
}
|
||||
data.put("events", tpmPcrEvents);
|
||||
} else {
|
||||
data.put("events", logProcessor.getEventList());
|
||||
}
|
||||
|
||||
getEventSummary(data, logProcessor.getEventList());
|
||||
return data;
|
||||
}
|
||||
|
||||
private static void getEventSummary(final HashMap<String, Object> data,
|
||||
final Collection<TpmPcrEvent> eventList) {
|
||||
boolean crtm = false;
|
||||
boolean bootManager = false;
|
||||
boolean osLoader = false;
|
||||
boolean osKernel = false;
|
||||
boolean acpiTables = false;
|
||||
boolean smbiosTables = false;
|
||||
boolean gptTable = false;
|
||||
boolean bootOrder = false;
|
||||
boolean defaultBootDevice = false;
|
||||
boolean secureBoot = false;
|
||||
boolean pk = false;
|
||||
boolean kek = false;
|
||||
boolean sigDb = false;
|
||||
boolean forbiddenDbx = false;
|
||||
|
||||
String contentStr;
|
||||
for (TpmPcrEvent tpe : eventList) {
|
||||
contentStr = tpe.getEventContentStr();
|
||||
// check for specific events
|
||||
if (contentStr.contains("CRTM")) {
|
||||
crtm = true;
|
||||
} else if (contentStr.contains("shimx64.efi")
|
||||
|| contentStr.contains("bootmgfw.efi")) {
|
||||
bootManager = true;
|
||||
} else if (contentStr.contains("grubx64.efi")
|
||||
|| contentStr.contains("winload.efi")) {
|
||||
osLoader = true;
|
||||
} else if (contentStr.contains("vmlinuz")
|
||||
|| contentStr.contains("ntoskrnl.exe")) {
|
||||
osKernel = true;
|
||||
} else if (contentStr.contains("ACPI")) {
|
||||
acpiTables = true;
|
||||
} else if (contentStr.contains("SMBIOS")) {
|
||||
smbiosTables = true;
|
||||
} else if (contentStr.contains("GPT")) {
|
||||
gptTable = true;
|
||||
} else if (contentStr.contains("BootOrder")) {
|
||||
bootOrder = true;
|
||||
} else if (contentStr.contains("Boot0000")) {
|
||||
defaultBootDevice = true;
|
||||
} else if (contentStr.contains("variable named PK")) {
|
||||
pk = true;
|
||||
} else if (contentStr.contains("variable named KEK")) {
|
||||
kek = true;
|
||||
} else if (contentStr.contains("variable named db")) {
|
||||
if (contentStr.contains("dbx")) {
|
||||
forbiddenDbx = true;
|
||||
} else {
|
||||
sigDb = true;
|
||||
}
|
||||
} else if (contentStr.contains("Secure Boot is enabled")) {
|
||||
secureBoot = true;
|
||||
}
|
||||
}
|
||||
|
||||
data.put("crtm", crtm);
|
||||
data.put("bootManager", bootManager);
|
||||
data.put("osLoader", osLoader);
|
||||
data.put("osKernel", osKernel);
|
||||
data.put("acpiTables", acpiTables);
|
||||
data.put("smbiosTables", smbiosTables);
|
||||
data.put("gptTable", gptTable);
|
||||
data.put("bootOrder", bootOrder);
|
||||
data.put("defaultBootDevice", defaultBootDevice);
|
||||
data.put("secureBoot", secureBoot);
|
||||
data.put("pk", pk);
|
||||
data.put("kek", kek);
|
||||
data.put("sigDb", sigDb);
|
||||
data.put("forbiddenDbx", forbiddenDbx);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes the place of an entire class for a string builder.
|
||||
* Gathers all information and returns it for displays.
|
||||
*
|
||||
* @param measurements established ReferenceManifest Type.
|
||||
* @param referenceManifestManager the reference manifest manager.
|
||||
* @param referenceEventManager the reference event manager.
|
||||
* @return mapping of the RIM information from the database.
|
||||
* @throws java.io.IOException error for reading file bytes.
|
||||
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
|
||||
* @throws CertificateException if a certificate doesn't parse.
|
||||
*/
|
||||
private static HashMap<String, Object> getMeasurementsRimInfo(
|
||||
final EventLogMeasurements measurements,
|
||||
final ReferenceManifestService referenceManifestManager,
|
||||
final ReferenceDigestValueService referenceEventManager)
|
||||
throws IOException, CertificateException, NoSuchAlgorithmException {
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
LinkedList<TpmPcrEvent> livelogEvents = new LinkedList<>();
|
||||
BaseReferenceManifest base = null;
|
||||
List<SupportReferenceManifest> supports = new ArrayList<>();
|
||||
SupportReferenceManifest baseSupport = null;
|
||||
|
||||
data.put("supportFilename", "Blank");
|
||||
data.put("supportId", "");
|
||||
data.put("associatedRim", "");
|
||||
data.put("rimType", measurements.getRimType());
|
||||
data.put("hostName", measurements.getDeviceName());
|
||||
data.put("validationResult", measurements.getOverallValidationResult());
|
||||
data.put("swidBase", true);
|
||||
|
||||
List<ReferenceDigestValue> eventValues = new ArrayList<>();
|
||||
if (measurements.getDeviceName() != null) {
|
||||
supports.addAll(SupportReferenceManifest
|
||||
.select(referenceManifestManager)
|
||||
.byDeviceName(measurements
|
||||
.getDeviceName()).getRIMs());
|
||||
for (SupportReferenceManifest support : supports) {
|
||||
if (support.isBaseSupport()) {
|
||||
baseSupport = support;
|
||||
}
|
||||
}
|
||||
|
||||
if (baseSupport != null) {
|
||||
data.put("supportFilename", baseSupport.getFileName());
|
||||
data.put("supportId", baseSupport.getId());
|
||||
|
||||
base = BaseReferenceManifest
|
||||
.select(referenceManifestManager)
|
||||
.byEntityId(baseSupport.getAssociatedRim())
|
||||
.getRIM();
|
||||
data.put("tagId", baseSupport.getTagId());
|
||||
|
||||
if (base != null) {
|
||||
data.put("associatedRim", base.getId());
|
||||
}
|
||||
|
||||
eventValues.addAll(referenceEventManager.getValuesByRimId(base));
|
||||
}
|
||||
}
|
||||
|
||||
TCGEventLog measurementLog = new TCGEventLog(measurements.getRimBytes());
|
||||
Map<String, ReferenceDigestValue> eventValueMap = new HashMap<>();
|
||||
|
||||
for (ReferenceDigestValue rdv : eventValues) {
|
||||
eventValueMap.put(rdv.getDigestValue(), rdv);
|
||||
}
|
||||
for (TpmPcrEvent measurementEvent : measurementLog.getEventList()) {
|
||||
if (!eventValueMap.containsKey(measurementEvent.getEventDigestStr())) {
|
||||
livelogEvents.add(measurementEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (!supports.isEmpty()) {
|
||||
Map<String, List<TpmPcrEvent>> baselineLogEvents = new HashMap<>();
|
||||
List<TpmPcrEvent> matchedEvents = null;
|
||||
List<TpmPcrEvent> combinedBaselines = new LinkedList<>();
|
||||
for (SupportReferenceManifest support : supports) {
|
||||
combinedBaselines.addAll(support.getEventLog());
|
||||
}
|
||||
String bootVariable;
|
||||
String variablePrefix = "Variable Name:";
|
||||
String variableSuffix = "UEFI_GUID";
|
||||
for (TpmPcrEvent tpe : livelogEvents) {
|
||||
matchedEvents = new ArrayList<>();
|
||||
for (TpmPcrEvent tpmPcrEvent : combinedBaselines) {
|
||||
if (tpmPcrEvent.getEventType() == tpe.getEventType()) {
|
||||
if (tpe.getEventContentStr().contains(variablePrefix)) {
|
||||
bootVariable = tpe.getEventContentStr().substring((
|
||||
tpe.getEventContentStr().indexOf(variablePrefix)
|
||||
+ variablePrefix.length()),
|
||||
tpe.getEventContentStr().indexOf(variableSuffix));
|
||||
if (tpmPcrEvent.getEventContentStr().contains(bootVariable)) {
|
||||
matchedEvents.add(tpmPcrEvent);
|
||||
}
|
||||
} else {
|
||||
matchedEvents.add(tpmPcrEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
baselineLogEvents.put(tpe.getEventDigestStr(), matchedEvents);
|
||||
}
|
||||
data.put("eventTypeMap", baselineLogEvents);
|
||||
}
|
||||
|
||||
TCGEventLog logProcessor = new TCGEventLog(measurements.getRimBytes());
|
||||
data.put("livelogEvents", livelogEvents);
|
||||
data.put("events", logProcessor.getEventList());
|
||||
getEventSummary(data, logProcessor.getEventList());
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package hirs.attestationca.portal.page.controllers;
|
||||
|
||||
import hirs.attestationca.persist.CriteriaModifier;
|
||||
import hirs.attestationca.persist.FilteredRecordsList;
|
||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||
import hirs.attestationca.persist.service.ReferenceDigestValueService;
|
||||
import hirs.attestationca.persist.service.ReferenceDigestValueServiceImpl;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestService;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
|
||||
import hirs.attestationca.portal.datatables.DataTableInput;
|
||||
import hirs.attestationca.portal.datatables.DataTableResponse;
|
||||
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
|
||||
import hirs.attestationca.portal.page.Page;
|
||||
import hirs.attestationca.portal.page.PageController;
|
||||
import hirs.attestationca.portal.page.params.NoPageParams;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.hibernate.Session;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
|
||||
/**
|
||||
* Controller for the Reference Manifest page.
|
||||
*/
|
||||
@Log4j2
|
||||
@Controller
|
||||
@RequestMapping("/reference-manifests")
|
||||
public class ReferenceManifestPageController extends PageController<NoPageParams> {
|
||||
|
||||
@Autowired(required = false)
|
||||
private EntityManager entityManager;
|
||||
|
||||
private final ReferenceManifestService referenceManifestManager;
|
||||
private final ReferenceDigestValueService referenceEventManager;
|
||||
|
||||
/**
|
||||
* Constructor providing the Page's display and routing specification.
|
||||
*
|
||||
* @param referenceManifestManager the reference manifest manager
|
||||
* @param referenceEventManager this is the reference event manager
|
||||
*/
|
||||
@Autowired
|
||||
public ReferenceManifestPageController(
|
||||
final ReferenceManifestServiceImpl referenceManifestManager,
|
||||
final ReferenceDigestValueServiceImpl referenceEventManager) {
|
||||
super(Page.REFERENCE_MANIFESTS);
|
||||
this.referenceManifestManager = referenceManifestManager;
|
||||
this.referenceEventManager = referenceEventManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filePath 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 filePath for the view and data model for the page.
|
||||
*/
|
||||
@Override
|
||||
public ModelAndView initPage(final NoPageParams params,
|
||||
final Model model) {
|
||||
return getBaseModelAndView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of RIMs using the data table input for paging, ordering,
|
||||
* and filtering.
|
||||
*
|
||||
* @param input the data tables input
|
||||
* @return the data tables response, including the result set and paging
|
||||
* information
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/list",
|
||||
produces = MediaType.APPLICATION_JSON_VALUE,
|
||||
method = RequestMethod.GET)
|
||||
public DataTableResponse<ReferenceManifest> getTableData(
|
||||
@Valid final DataTableInput input) {
|
||||
log.info("Handling request for summary list: " + input);
|
||||
|
||||
// return this.referenceManifestManager.fetchReferenceManifests(input);
|
||||
|
||||
String orderColumnName = input.getOrderColumnName();
|
||||
log.debug("Ordering on column: " + orderColumnName);
|
||||
|
||||
// check that the alert is not archived and that it is in the specified report
|
||||
CriteriaModifier criteriaModifier = new CriteriaModifier() {
|
||||
@Override
|
||||
public void modify(final CriteriaQuery criteriaQuery) {
|
||||
Session session = entityManager.unwrap(Session.class);
|
||||
CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
Root<ReferenceManifest> rimRoot = criteriaQuery.from(Reference.class);
|
||||
|
||||
criteriaQuery.select(rimRoot).distinct(true).where(cb.isNull(rimRoot.get(Certificate.ARCHIVE_FIELD)));
|
||||
// criteria.add(Restrictions.isNull(Certificate.ARCHIVE_FIELD));
|
||||
}
|
||||
};
|
||||
FilteredRecordsList<ReferenceManifest> records
|
||||
= OrderedListQueryDataTableAdapter.getOrderedList(
|
||||
ReferenceManifest.class,
|
||||
referenceManifestManager,
|
||||
input, orderColumnName, criteriaModifier);
|
||||
|
||||
log.debug("Returning list of size: " + records.size());
|
||||
return new DataTableResponse<>(records, input);
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package hirs.attestationca.portal.page.controllers;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
|
||||
import hirs.attestationca.persist.service.ReferenceDigestValueService;
|
||||
import hirs.attestationca.persist.service.ReferenceDigestValueServiceImpl;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestService;
|
||||
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
|
||||
import hirs.attestationca.portal.page.Page;
|
||||
import hirs.attestationca.portal.page.PageController;
|
||||
import hirs.attestationca.portal.page.params.NoPageParams;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.datatables.mapping.DataTablesInput;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Controller for the TPM Events page.
|
||||
*/
|
||||
@Log4j2
|
||||
@Controller
|
||||
@RequestMapping("/rim-database")
|
||||
public class RimDatabasePageController extends PageController<NoPageParams> {
|
||||
|
||||
private final ReferenceManifestService referenceManifestManager;
|
||||
private final ReferenceDigestValueService referenceEventManager;
|
||||
|
||||
/**
|
||||
* Constructor providing the Page's display and routing specification.
|
||||
*
|
||||
* @param referenceManifestManager the ReferenceManifestManager object
|
||||
* @param referenceEventManager the referenceEventManager object
|
||||
*/
|
||||
@Autowired
|
||||
public RimDatabasePageController(final ReferenceManifestServiceImpl referenceManifestManager,
|
||||
final ReferenceDigestValueServiceImpl referenceEventManager) {
|
||||
super(Page.RIM_DATABASE);
|
||||
this.referenceManifestManager = referenceManifestManager;
|
||||
this.referenceEventManager = referenceEventManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filePath 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 filePath for the view and data model for the page.
|
||||
*/
|
||||
@Override
|
||||
public ModelAndView initPage(final NoPageParams params,
|
||||
final Model model) {
|
||||
return getBaseModelAndView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of TPM Events using the data table input for paging, ordering,
|
||||
* and filtering.
|
||||
*
|
||||
* @param input the data tables input
|
||||
* @return the data tables response, including the result set and paging
|
||||
* information
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/list",
|
||||
produces = MediaType.APPLICATION_JSON_VALUE,
|
||||
method = RequestMethod.GET)
|
||||
public List<ReferenceDigestValue> getTableData(
|
||||
@Valid final DataTablesInput input) {
|
||||
log.info("Handling request for summary list: " + input);
|
||||
|
||||
return this.referenceEventManager.fetchDigestValues();
|
||||
|
||||
|
||||
// String orderColumnName = input.getOrderColumnName();
|
||||
// log.info("Ordering on column: " + orderColumnName);
|
||||
//
|
||||
// // check that the alert is not archived and that it is in the specified report
|
||||
// CriteriaModifier criteriaModifier = new CriteriaModifier() {
|
||||
// @Override
|
||||
// public void modify(final Criteria criteria) {
|
||||
// criteria.add(Restrictions.isNull(Certificate.ARCHIVE_FIELD));
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// log.info("Querying with the following datatableinput: " + input.toString());
|
||||
//
|
||||
// FilteredRecordsList<ReferenceDigestValue> referenceDigestValues =
|
||||
// OrderedListQueryDataTableAdapter.getOrderedList(
|
||||
// ReferenceDigestValue.class,
|
||||
// referenceEventManager,
|
||||
// input, orderColumnName, criteriaModifier);
|
||||
//
|
||||
// SupportReferenceManifest support;
|
||||
// for (ReferenceDigestValue rdv : referenceDigestValues) {
|
||||
// // We are updating the base rim ID field if necessary and
|
||||
// if (rdv.getBaseRimId() == null) {
|
||||
// support = SupportReferenceManifest.select(referenceManifestManager)
|
||||
// .byEntityId(rdv.getSupportRimId()).getRIM();
|
||||
// if (support != null) {
|
||||
// rdv.setBaseRimId(support.getAssociatedRim());
|
||||
// try {
|
||||
// referenceEventManager.updateRefDigestValue(rdv);
|
||||
// } catch (DBManagerException e) {
|
||||
// log.error("Failed to update TPM Event with Base RIM ID");
|
||||
// log.error(rdv);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return new DataTableResponse<>(referenceDigestValues, input);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,37 @@
|
||||
# General notes:
|
||||
# Properties are processed using an expression processor. That said, properties can inherit the
|
||||
# values of other properties.
|
||||
#
|
||||
# In example the processor will resolve the value of aca.both as 'hello world!'.
|
||||
# aca.hello = hello
|
||||
# aca.world = world!
|
||||
# aca.both = ${aca.hello} ${aca.world}
|
||||
#
|
||||
# ACA Directories
|
||||
# root: the root directory of ACA related files
|
||||
# certificates: the directory for ACA certificate files
|
||||
aca.directories.root = /etc/hirs/aca
|
||||
aca.directories.certificates = ${aca.directories.root}/certificates
|
||||
|
||||
# ACA certificate related properties. These are generic properties that apply to the creation of
|
||||
# any certificate that the ACA is responsible for creating.
|
||||
# validity: the number of days that credentials generated by the ACA are valid.
|
||||
aca.certificates.validity = 3652
|
||||
|
||||
# ACA key store properties
|
||||
# alias: the alias to reference the ACA key and certificate by
|
||||
# location: the absolute path to the ACA key store.
|
||||
# password: key store password
|
||||
aca.keyStore.alias = HIRS_ACA_KEY
|
||||
aca.keyStore.location = ${aca.directories.certificates}/keyStore.jks
|
||||
aca.keyStore.password =
|
||||
|
||||
# ACA setup/initialization properties. These properties are used exclusively by the ACA
|
||||
# initialization process. Generally these properties do not need to be modified
|
||||
#
|
||||
# keySize: the default key size of the ACA key pair stored within the trust store
|
||||
# subjectName: the CN of the generate X509 certificate
|
||||
# expiration: the number of days that the generated X509 certificate will expire
|
||||
aca.setup.keyStore.keySize = 2048
|
||||
aca.setup.keyStore.subjectName = HIRS_AttestationCA_Endorsement
|
||||
aca.setup.keyStore.expiration = ${aca.certificates.validity}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,964 @@
|
||||
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
<%-- JSP TAGS--%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%--CONTENT--%>
|
||||
<my:page>
|
||||
<jsp:attribute name="style">
|
||||
<link type="text/css" rel="stylesheet" href="${common}/certificate_details.css"/>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">
|
||||
<c:choose>
|
||||
<c:when test="${param.type=='certificateauthority'}">
|
||||
Certificate Authority
|
||||
<a href="${portal}/certificate-request/trust-chain/download?id=${param.id}">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download Certificate">
|
||||
</a>
|
||||
</c:when>
|
||||
<c:when test="${param.type=='endorsement'}">
|
||||
Endorsement Certificate
|
||||
<a href="${portal}/certificate-request/endorsement-key-credentials/download?id=${param.id}">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download Certificate">
|
||||
</a>
|
||||
</c:when>
|
||||
<c:when test="${param.type=='platform'}">
|
||||
Platform Certificate
|
||||
<a href="${portal}/certificate-request/platform-credentials/download?id=${param.id}">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download Certificate">
|
||||
</a>
|
||||
</c:when>
|
||||
<c:when test="${param.type=='issued'}">
|
||||
Issued Attestation Certificates
|
||||
<a href="${portal}/certificate-request/issued-certificates/download?id=${param.id}">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download Certificate">
|
||||
</a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
Unknown Certificate
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</jsp:attribute>
|
||||
|
||||
<jsp:body>
|
||||
<div id="certificate-details-page" class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Issuer</span></div>
|
||||
<div id="issuer" class="col col-md-8">
|
||||
<!-- Display the issuer, and provide a link to the issuer details if provided -->
|
||||
<div>Distinguished Name: <span>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.issuerID}">
|
||||
<a href="${portal}/certificate-details?id=${initialData.issuerID}&type=certificateauthority">
|
||||
${initialData.issuer}
|
||||
</a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${initialData.issuer}
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</div>
|
||||
<div>Authority Key Identifier:
|
||||
<span id="authorityKeyIdentifier"></span>
|
||||
</div>
|
||||
<c:if test="${not empty initialData.authInfoAccess}">
|
||||
<div>Authority Info Access: <span>
|
||||
<a href="${initialData.authInfoAccess}">${initialData.authInfoAccess}</a>
|
||||
</span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.authSerialNumber}">
|
||||
<div>Authority Serial Number:
|
||||
<span id="authSerialNumber"></span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${param.type!='issued'}">
|
||||
<span class="chainIcon">
|
||||
<!-- Icon with link for missing certificate for the chain -->
|
||||
<c:choose>
|
||||
<c:when test="${initialData.isSelfSigned == 'true'}">
|
||||
<img src="${icons}/ic_all_inclusive_black_24dp.png"
|
||||
title="Self sign certificate.">
|
||||
</c:when>
|
||||
<c:when test="${empty initialData.missingChainIssuer}">
|
||||
<img src="${icons}/ic_checkbox_marked_circle_black_green_24dp.png"
|
||||
title="All certificates in the chain were found.">
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<img src="${icons}/ic_error_red_24dp.png"
|
||||
title="${initialData.missingChainIssuer}">
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
<c:if test="${not empty initialData.subject}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Subject</span></div>
|
||||
<div id="subject" class="col col-md-8">${initialData.subject}</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.serialNumber}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Serial Number</span></div>
|
||||
<div id="serialNumber" class="col col-md-8 vertical"></div>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.beginValidity}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Validity</span></div>
|
||||
<div id="validity" class="col col-md-8">
|
||||
<div>Not Before: <span>${initialData.beginValidity}</span></div>
|
||||
<div>Not After: <span>${initialData.endValidity}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Signature</span></div><div id="signatureSection" class="col col-md-8">
|
||||
<div class="panel-body">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#signatureComponentcollapse"
|
||||
aria-expanded="true" data-placement="top" aria-controls="signatureComponentcollapse">
|
||||
Signature
|
||||
</a>
|
||||
</div>
|
||||
<div id="signatureComponentcollapse" class="panel-body collapse" role="tabpanel" aria-labelledby="headingOne" aria-expanded="false">
|
||||
<div id="signature" class="fieldValue"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#signatureSizecollapse"
|
||||
aria-expanded="true" data-placement="top" aria-controls="signatureSizecollapse">
|
||||
Algorithm
|
||||
</a>
|
||||
</div>
|
||||
<div id="signatureSizecollapse" class="panel-body collapse" role="tabpanel" aria-labelledby="headingOne" aria-expanded="false">
|
||||
<div>
|
||||
<span class="fieldValue">
|
||||
${initialData.signatureAlgorithm} / ${initialData.signatureSize}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<c:if test="${not empty initialData.encodedPublicKey}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Public Key</span></div>
|
||||
<div id="publicKeySection" class="col col-md-8">
|
||||
<div class="panel-body">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#publicKeycollapse"
|
||||
aria-expanded="true" data-placement="top" aria-controls="publicKeycollapse">
|
||||
Public Key
|
||||
</a>
|
||||
</div>
|
||||
<div id="publicKeycollapse" class="panel-body collapse" role="tabpanel" aria-labelledby="headingOne" aria-expanded="false">
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.publicKeyValue}">
|
||||
<div id="encodedPublicKey" class="fieldValue"></div>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div id="encodedPublicKey" class="fieldValue"></div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#publicKeySizecollapse"
|
||||
aria-expanded="true" data-placement="top" aria-controls="publicKeySizecollapse">
|
||||
Algorithm
|
||||
</a>
|
||||
</div>
|
||||
<div id="publicKeySizecollapse" class="panel-body collapse" role="tabpanel" aria-expanded="false">
|
||||
<div>
|
||||
<span class="fieldValue">
|
||||
${initialData.publicKeyAlgorithm} / ${initialData.publicKeySize}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">X509 Credential Version</span></div>
|
||||
<div id="credentialVersion" class="col col-md-8 vertical">${initialData.x509Version} (v${initialData.x509Version + 1})</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Credential Type</span></div>
|
||||
<div id="credentialType" class="col col-md-8 vertical">${initialData.credentialType}</div>
|
||||
</div>
|
||||
<!-- Add the different fields based on the certificate type -->
|
||||
<c:choose>
|
||||
<c:when test="${param.type=='certificateauthority'}">
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.subjectKeyIdentifier}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Subject Key Identifier</span></div>
|
||||
<div id="subjectKeyIdentifier" class="col col-md-8 vertical"></div>
|
||||
</div>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
<c:if test="${initialData.crlPoints}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Revocation Locator</span></div>
|
||||
<div id="revocationLocator" class="col col-md-8"><a href="${initialData.crlPoints}">${initialData.crlPoints}</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Key Usage</span></div>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.keyUsage}">
|
||||
<div id="keyUsage" class="col col-md-8 vertical">${initialData.keyUsage}</div>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div id="keyUsage" class="col col-md-8 vertical">Not Specified</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.extendedKeyUsage}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Extended Key Usage</span></div>
|
||||
<div id="extendedKeyUsage" class="col col-md-8 vertical">${initialData.extendedKeyUsage}</div>
|
||||
</div>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
</c:when>
|
||||
<c:when test="${param.type=='endorsement'}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">System Information</span></div>
|
||||
<div id="subjectAltName" class="col col-md-8">
|
||||
<div id="manufacturer">Manufacturer: <span>${initialData.manufacturer}</span></div>
|
||||
<div id="model">Model: <span>${initialData.model}</span></div>
|
||||
<div id="version">Version: <span>${initialData.version}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Policy Reference</span></div>
|
||||
<div id="policyReference" class="col col-md-8 vertical">
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.policyReference}">
|
||||
${initialData.policyReference}
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
Not Specified
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
<c:if test="${initialData.crlPoints}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Revocation Locator</span></div>
|
||||
<div id="revocationLocator" class="col col-md-8"><a href="${initialData.crlPoints}">${initialData.crlPoints}</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Key Usage</span></div>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.keyUsage}">
|
||||
<div id="keyUsage" class="col col-md-8 vertical">${initialData.keyUsage}</div>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div id="keyUsage" class="col col-md-8 vertical">Not Specified</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.extendedKeyUsage}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Extended Key Usage</span></div>
|
||||
<div id="extendedKeyUsage" class="col col-md-8 vertical">${initialData.extendedKeyUsage}</div>
|
||||
</div>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1">
|
||||
<span class="colHeader">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#tpmSpecificationInner"
|
||||
aria-expanded="true" data-placement="top" aria-controls="tpmSpecificationInner">
|
||||
TPM Specification
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div id="tpmSpecification" class="col col-md-8">
|
||||
<div id="tpmSpecificationInner" class="panel-body collapse" role="tabpanel" aria-expanded="false">
|
||||
<div>Family: <span>${initialData.TPMSpecificationFamily}</span></div>
|
||||
<div>Level: <span>${initialData.TPMSpecificationLevel}</span></div>
|
||||
<div>Revision: <span>${initialData.TPMSpecificationRevision}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1">
|
||||
<span class="colHeader">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#tpmSecurityAssertionInner"
|
||||
aria-expanded="true" data-placement="top" aria-controls="tpmSecurityAssertionInner">
|
||||
TPM Security Assertion
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div id="tpmSecurityAssertion" class="col col-md-8">
|
||||
<div id="tpmSecurityAssertionInner" class="panel-body collapse" role="tabpanel" aria-expanded="false">
|
||||
<div>Version: <span>${initialData.TPMSecurityAssertionsVersion}</span></div>
|
||||
<div>Field Upgradeable: <span>${initialData.TPMSecurityAssertionsFieldUpgradeable}</span></div>
|
||||
<div>ek Generation Type: <span>${initialData.TPMSecurityAssertionsEkGenType}</span></div>
|
||||
<div>ek Generation Location: <span>${initialData.TPMSecurityAssertionsEkGenLoc}</span></div>
|
||||
<div>ek Certificate Generation Location: <span>${initialData.TPMSecurityAssertionsEkCertGenLoc}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:when>
|
||||
<c:when test="${param.type=='platform'}">
|
||||
<c:if test="${not empty initialData.platformType}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Platform Type</span></div>
|
||||
<div id="platformType" class="col col-md-8 vertical">${initialData.platformType}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Platform Chain</span></div>
|
||||
<div id="platformType" class="col col-md-8 vertical">
|
||||
<span>
|
||||
<c:forEach items="${initialData.chainCertificates}" var="credential" varStatus="loop">
|
||||
<c:choose>
|
||||
<c:when test="${initialData.certificateId==credential.getId().toString()}">
|
||||
${loop.index}
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="${portal}/certificate-details?id=${credential.getId()}&type=platform">${loop.index}</a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:forEach>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.CPSuri}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Certification Practice Statement URI</span></div>
|
||||
<div id="certificateCPSU" class="col col-md-8 vertical">
|
||||
<a href="${initialData.CPSuri}"> ${initialData.CPSuri}</a>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Holder</span></div>
|
||||
<div id="holder" class="col col-md-8">
|
||||
<c:if test="${not empty initialData.holderIssuer}">
|
||||
<div>Holder Certificate: <span>${initialData.holderIssuer}</span></div>
|
||||
</c:if>
|
||||
<div id="certificateid">
|
||||
<div>Holder Identifier:
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.holderId}">
|
||||
<span>
|
||||
<c:choose>
|
||||
<c:when test="${(not empty initialData.platformType) and (initialData.platformType=='Delta')}">
|
||||
<a href="${portal}/certificate-details?id=${initialData.holderId}&type=platform">
|
||||
${initialData.holderSerialNumber}
|
||||
</a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="${portal}/certificate-details?id=${initialData.holderId}&type=endorsement">
|
||||
${initialData.holderSerialNumber}
|
||||
</a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span>${initialData.holderSerialNumber}</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">System Platform Information</span></div>
|
||||
<div id="subjectAltName" class="col col-md-8">
|
||||
<div id="manufacturer">Manufacturer: <span>${initialData.manufacturer}</span></div>
|
||||
<div id="model">Model: <span>${initialData.model}</span></div>
|
||||
<div id="version">Version: <span>${initialData.version}</span></div>
|
||||
<div id="serial">Serial Number: <span>${initialData.platformSerial}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">TCG Platform Specification Version</span></div>
|
||||
<div id="majorVersion" class="col col-md-8 vertical">${initialData.majorVersion}.${initialData.minorVersion}.${initialData.revisionLevel}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Platform Class</span></div>
|
||||
<div id="platformClass" class="col col-md-8 vertical">${initialData.platformClass}</div>
|
||||
</div>
|
||||
<!-- TBB Security Assertion-->
|
||||
<c:if test="${not empty initialData.tbbSecurityAssertion}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">TBB Security Assertion</span></div>
|
||||
<div id="tbbsecurity" class="col col-md-8">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Version:</span>
|
||||
<span class="fieldValue">${initialData.tbbSecurityAssertion.getVersion()} (v${initialData.tbbSecurityAssertion.getVersion().getValue() + 1})</span>
|
||||
</div>
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">RTM (Root of Trust of Measurement):</span>
|
||||
<span class="fieldValue">${fn:toUpperCase(initialData.tbbSecurityAssertion.getRtmType().getValue())}</span>
|
||||
</div>
|
||||
<!-- CCINFO -->
|
||||
<c:if test="${not empty initialData.tbbSecurityAssertion.getCcInfo()}">
|
||||
<c:set var="ccinfo" value="${initialData.tbbSecurityAssertion.getCcInfo()}" />
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingOne">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#tbbsecurity" class="collapsed"
|
||||
href="#ccinfocollapse" aria-expanded="false" aria-controls="ccinfocollapse">
|
||||
Common Criteria Measures Information
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="ccinfocollapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
|
||||
<div class="panel-body">
|
||||
<div id="ccinfo" class="row">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Version:</span>
|
||||
<span class="fieldValue">${ccinfo.getVersion()}</span>
|
||||
</div>
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Assurance Level:</span>
|
||||
<span class="fieldValue">${fn:toUpperCase(ccinfo.getAssurancelevel().getValue())}</span>
|
||||
</div>
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Evaluation Status:</span>
|
||||
<span class="fieldValue">${fn:toUpperCase(ccinfo.getEvaluationStatus().getValue())}</span>
|
||||
</div>
|
||||
<div class="tbbsecurityLine">
|
||||
<c:choose>
|
||||
<c:when test="${ccinfo.getPlus()=='TRUE'}">
|
||||
<span class="label label-success">Plus</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="label label-danger">Not Plus</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Strength of Function:</span>
|
||||
<span class="fieldValue">${fn:toUpperCase(ccinfo.getStrengthOfFunction().getValue())}</span>
|
||||
</div>
|
||||
<c:if test="${not empty ccinfo.getProfileOid()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Profile OID:</span>
|
||||
<span class="fieldValue">${ccinfo.getProfileOid()}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty ccinfo.getProfileUri()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Profile URI:</span>
|
||||
<span class="fieldValue">
|
||||
<a href="${ccinfo.getProfileUri().getUniformResourceIdentifier()}">
|
||||
${ccinfo.getProfileUri().getUniformResourceIdentifier()}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<c:if test="${not empty ccinfo.getProfileUri().getHashAlgorithm()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Profile Hash Algorithm:</span>
|
||||
<span class="fieldValue">${ccinfo.getProfileUri().getHashAlgorithm()}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty ccinfo.getProfileUri().getHashValue()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Profile Hash Value:</span>
|
||||
<span class="fieldValue">${ccinfo.getProfileUri().getHashValue()}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</c:if>
|
||||
<c:if test="${not empty ccinfo.getTargetOid()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Target OID:</span>
|
||||
<span class="fieldValue">${ccinfo.getTargetOid()}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty ccinfo.getTargetUri()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Target URI:</span>
|
||||
<span class="fieldValue">
|
||||
<a href="${ccinfo.getTargetUri().getUniformResourceIdentifier()}">
|
||||
${ccinfo.getTargetUri().getUniformResourceIdentifier()}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<c:if test="${not empty ccinfo.getTargetUri().getHashAlgorithm()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Target Hash Algorithm:</span>
|
||||
<span class="fieldValue">${ccinfo.getTargetUri().getHashAlgorithm()}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty ccinfo.getTargetUri().getHashValue()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Target Hash Value:</span>
|
||||
<span class="fieldValue">${ccinfo.getTargetUri().getHashValue()}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<!-- FIPS Level -->
|
||||
<c:if test="${not empty initialData.tbbSecurityAssertion.getFipsLevel()}">
|
||||
<c:set var="fipslevel" value="${initialData.tbbSecurityAssertion.getFipsLevel()}" />
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingThree">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#tbbsecurity" class="collapsed"
|
||||
href="#fipscollapse" aria-expanded="false" aria-controls="fipscollapse">
|
||||
FIPS Level
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="fipscollapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo">
|
||||
<div class="panel-body">
|
||||
<div id="fipsLevel" class="row">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Version:</span>
|
||||
<span class="fieldValue">${fipslevel.getVersion()}</span>
|
||||
</div>
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">Level:</span>
|
||||
<span class="fieldValue">${fn:toUpperCase(fipslevel.getLevel().getValue())}</span>
|
||||
</div>
|
||||
<div class="tbbsecurityLine">
|
||||
<c:choose>
|
||||
<c:when test="${fipslevel.getPlus()=='TRUE'}">
|
||||
<span class="label label-success">Plus</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="label label-danger">Not Plus</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<!-- ISO9000 isCertified and URI -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingThree">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#tbbsecurity" class="collapsed"
|
||||
href="#iso9000collapse" aria-expanded="false" aria-controls="iso9000collapse">
|
||||
ISO 9000
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="iso9000collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
|
||||
<div class="panel-body">
|
||||
<div id="iso9000" class="row">
|
||||
<div class="tbbsecurityLine">
|
||||
<c:choose>
|
||||
<c:when test="${initialData.tbbSecurityAssertion.getIso9000Certified()=='TRUE'}">
|
||||
<span class="label label-success">ISO 9000 Certified</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="label label-danger">ISO 9000 Not Certified</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
<c:if test="${not empty initialData.tbbSecurityAssertion.getIso9000Uri()}">
|
||||
<div class="tbbsecurityLine">
|
||||
<span class="fieldHeader">URI:</span>
|
||||
<span class="fieldValue">
|
||||
<a href="${initialData.tbbSecurityAssertion.getIso9000Uri()}">
|
||||
${initialData.tbbSecurityAssertion.getIso9000Uri()}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<!-- For PC 2.0 -->
|
||||
<c:if test="${fn:contains(initialData.credentialType, 'TCG')}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">TCG Platform Configuration</span></div>
|
||||
<div id="platformConfiguration" class="col col-md-8">
|
||||
<c:if test="${not empty initialData.componentsIdentifier}">
|
||||
<!-- Component Identifier -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingOne">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#platformConfiguration" class="collapsed"
|
||||
href="#componentIdentifiercollapse" aria-expanded="true" aria-controls="componentIdentifiercollapse">
|
||||
Components
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="componentIdentifiercollapse" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne" aria-expanded="true">
|
||||
<div class="panel-body">
|
||||
<div id="componentIdentifier" class="row">
|
||||
<c:forEach items="${initialData.componentsIdentifier}" var="component">
|
||||
<c:set var="combined" value="${component.hashCode()}" scope="page"/>
|
||||
<div class="component col col-md-4">
|
||||
<div class="panel panel-default">
|
||||
<c:choose>
|
||||
<c:when test="${fn:contains(initialData.failures, combined)}">
|
||||
<div class="panel-heading" style="background-color: red; color: white">
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="panel-heading">
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<c:choose>
|
||||
<c:when test="${component.isVersion2()=='TRUE'}">
|
||||
<span data-toggle="tooltip" data-placement="top" title="Component Class">${component.getComponentClass()}</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span data-toggle="tooltip" data-placement="top" title="Component Class">Platform Components</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<span class="fieldHeader">Manufacturer:</span>
|
||||
<span class="fieldValue">${component.getComponentManufacturer()}</span><br/>
|
||||
<span class="fieldHeader">Model:</span>
|
||||
<span class="fieldValue">${component.getComponentModel()}</span><br/>
|
||||
<c:if test="${not empty fn:trim(component.getComponentSerial())}">
|
||||
<span class="fieldHeader">Serial Number:</span>
|
||||
<span class="fieldValue">${component.getComponentSerial()}</span><br/>
|
||||
</c:if>
|
||||
<c:if test="${not empty fn:trim(component.getComponentRevision())}">
|
||||
<span class="fieldHeader">Revision:</span>
|
||||
<span class="fieldValue">${component.getComponentRevision()}</span><br/>
|
||||
</c:if>
|
||||
<c:forEach items="${component.getComponentAddress()}" var="address">
|
||||
<span class="fieldHeader">${address.getAddressTypeValue()} address:</span>
|
||||
<span class="fieldValue">${address.getAddressValue()}</span><br/>
|
||||
</c:forEach>
|
||||
<c:choose>
|
||||
<c:when test="${component.getFieldReplaceable()=='TRUE'}">
|
||||
<span class="label label-success">Replaceable</span><br/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="label label-danger">Irreplaceable</span><br/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<c:if test="${component.isVersion2()}">
|
||||
<c:if test="${not empty component.getCertificateIdentifier()}">
|
||||
<span class="fieldHeader">Platform Certificate Issuer:</span>
|
||||
<span class="fieldValue">${component.getCertificateIdentifier().getIssuerDN()}</span><br />
|
||||
<span class="fieldHeader">Platform Certificate Serial Number:</span>
|
||||
<span class="fieldValue">${component.getCertificateIdentifier().getCertificateSerialNumber()}</span><br />
|
||||
<span class="fieldHeader">Platform Certificate URI:</span>
|
||||
</c:if>
|
||||
<span class="fieldValue">
|
||||
<a href="${component.getComponentPlatformUri().getUniformResourceIdentifier()}">
|
||||
${component.getComponentPlatformUri().getUniformResourceIdentifier()}
|
||||
</a>
|
||||
</span><br />
|
||||
<span class="fieldHeader">Status:</span>
|
||||
<span class="fieldValue">${component.getAttributeStatus()}</span><br/>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:forEach>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.componentsIdentifierURI}">
|
||||
<!-- Components Identifier URI -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingTwo">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#platformConfiguration" class="collapsed"
|
||||
href="#componentIdentifierURIcollapse" aria-expanded="false" aria-controls="componentIdentifierURIcollapse">
|
||||
Components Identifier URI
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="componentIdentifierURIcollapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo">
|
||||
<div class="panel-body">
|
||||
<div id="componentIdentifierURI" class="row">
|
||||
<span class="fieldHeader">URI:</span>
|
||||
<a href="${initialData.componentsIdentifierURI.getUniformResourceIdentifier()}">
|
||||
${initialData.componentsIdentifierURI.getUniformResourceIdentifier()}
|
||||
</a>
|
||||
<c:if test="${not empty initialData.componentsIdentifierURI.getHashAlgorithm()}">
|
||||
<span class="fieldHeader">Hash Algorithm:</span>
|
||||
<span>${initialData.componentsIdentifierURI.getHashAlgorithm()}</span>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.componentsIdentifierURI.getHashValue()}">
|
||||
<span class="fieldHeader">Hash Value:</span>
|
||||
<span>${initialData.componentsIdentifierURI.getHashValue()}</span>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.platformProperties}">
|
||||
<!-- Platform Properties -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingThree">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#platformConfiguration" class="collapsed"
|
||||
href="#platformPropertiescollapse" aria-expanded="false" aria-controls="platformPropertiescollapse">
|
||||
Platform Properties
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="platformPropertiescollapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
|
||||
<div class="panel-body">
|
||||
<div id="platformProperties" class="row">
|
||||
<c:forEach items="${initialData.platformProperties}" var="property">
|
||||
<div class="component col col-md-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<span class="fieldHeader">Name:</span>
|
||||
<span class="fieldValue">${property.getPropertyName()}</span><br/>
|
||||
<span class="fieldHeader">Value:</span>
|
||||
<span class="fieldValue" style="word-wrap: break-word">${property.getPropertyValue()}</span><br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:forEach>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.platformPropertiesURI}">
|
||||
<!-- Platform Properties URI -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingFour">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#platformConfiguration" class="collapsed"
|
||||
href="#platformPropertiesURIcollapse" aria-expanded="false" aria-controls="platformPropertiesURIcollapse">
|
||||
Platform Properties URI
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="platformPropertiesURIcollapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingFour">
|
||||
<div class="panel-body">
|
||||
<div id="platformPropertiesURI" class="row">
|
||||
<span class="fieldHeader">URI:</span>
|
||||
<a href="${initialData.platformPropertiesURI.getUniformResourceIdentifier()}">
|
||||
${initialData.platformPropertiesURI.getUniformResourceIdentifier()}
|
||||
</a>
|
||||
<c:if test="${not empty initialData.platformPropertiesURI.getHashAlgorithm()}">
|
||||
<span class="fieldHeader">Hash Algorithm:</span>
|
||||
<span>${initialData.platformPropertiesURI.getHashAlgorithm()}</span>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.platformPropertiesURI.getHashValue()}">
|
||||
<span class="fieldHeader">Hash Value:</span>
|
||||
<span>${initialData.platformPropertiesURI.getHashValue()}</span>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
</div><!-- close platformConfiguration -->
|
||||
</div> <!-- Close row -->
|
||||
</c:if>
|
||||
</c:when>
|
||||
<c:when test="${param.type=='issued'}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">System Information</span></div>
|
||||
<div id="subjectAltName" class="col col-md-8">
|
||||
<div id="manufacturer">Manufacturer: <span>${initialData.manufacturer}</span></div>
|
||||
<div id="model">Model: <span>${initialData.model}</span></div>
|
||||
<div id="version">Version: <span>${initialData.version}</span></div>
|
||||
<div id="serial">Serial Number: <span>${initialData.platformSerial}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Policy Reference</span></div>
|
||||
<div id="policyReference" class="col col-md-8 vertical">
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.policyReference}">
|
||||
${initialData.policyReference}
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
Not Specified
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
<c:if test="${initialData.crlPoints}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Revocation Locator</span></div>
|
||||
<div id="revocationLocator" class="col col-md-8"><a href="${initialData.crlPoints}">${initialData.crlPoints}</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Endorsement Credential</span></div>
|
||||
<div id="endorsementID" class="col col-md-8">
|
||||
<c:if test="${not empty initialData.endorsementID}">
|
||||
<a href="${portal}/certificate-details?id=${initialData.endorsementID}&type=endorsement">
|
||||
<img src="${icons}/ic_vpn_key_black_24dp.png">
|
||||
</a>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Platform Credentials</span></div>
|
||||
<div id="platformID" class="col col-md-8">
|
||||
<c:if test="${not empty initialData.platformID}">
|
||||
<c:forTokens items = "${initialData.platformID}" delims = "," var = "pcID">
|
||||
<a href="${portal}/certificate-details?id=${pcID}&type=platform">
|
||||
<img src="${icons}/ic_important_devices_black_24dp.png">
|
||||
</a>
|
||||
</c:forTokens>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">TCG Platform Specification Version</span></div>
|
||||
<div id="majorVersion" class="col col-md-8 vertical">${initialData.majorVersion}.${initialData.minorVersion}.${initialData.revisionLevel}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">TCG Credential Specification Version</span></div>
|
||||
<div id="majorVersion" class="col col-md-8 vertical">${initialData.tcgMajorVersion}.${initialData.tcgMinorVersion}.${initialData.tcgRevisionLevel}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1">
|
||||
<span class="colHeader">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#tpmSpecificationInner"
|
||||
aria-expanded="true" data-placement="top" aria-controls="tpmSpecificationInner">
|
||||
TPM Specification
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div id="tpmSpecification" class="col col-md-8">
|
||||
<div id="tpmSpecificationInner" class="panel-body collapse" role="tabpanel" aria-expanded="false">
|
||||
<div>Family: <span>${initialData.TPMSpecificationFamily}</span></div>
|
||||
<div>Level: <span>${initialData.TPMSpecificationLevel}</span></div>
|
||||
<div>Revision: <span>${initialData.TPMSpecificationRevision}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1">
|
||||
<span class="colHeader">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#tpmSecurityAssertionInner"
|
||||
aria-expanded="true" data-placement="top" aria-controls="tpmSecurityAssertionInner">
|
||||
TPM Security Assertion
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div id="tpmSecurityAssertion" class="col col-md-8">
|
||||
<div id="tpmSecurityAssertionInner" class="panel-body collapse" role="tabpanel" aria-expanded="false">
|
||||
<div>Version: <span>${initialData.TPMSecurityAssertionsVersion}</span></div>
|
||||
<div>Field Upgradeable: <span>${initialData.TPMSecurityAssertionsFieldUpgradeable}</span></div>
|
||||
<div>ek Generation Type: <span>${initialData.TPMSecurityAssertionsEkGenType}</span></div>
|
||||
<div>ek Generation Location: <span>${initialData.TPMSecurityAssertionsEkGenLoc}</span></div>
|
||||
<div>ek Certificate Generation Location: <span>${initialData.TPMSecurityAssertionsEkCertGenLoc}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
var type = "${param.type}";
|
||||
var signature = ${initialData.signature};
|
||||
var serialNumber = '${initialData.serialNumber}';
|
||||
var authorityKeyIdentifier = '${initialData.authKeyId}';
|
||||
var authoritySerialNumber = '${initialData.authSerialNumber}';
|
||||
|
||||
//Format validity time
|
||||
$("#validity span").each(function () {
|
||||
$(this).text(formatDateTime($(this).text()));
|
||||
});
|
||||
|
||||
//Convert byte array to string
|
||||
$("#signature").html(byteToHexString(signature));
|
||||
|
||||
//Convert byte array to string
|
||||
$("#serialNumber").html(parseSerialNumber(serialNumber));
|
||||
|
||||
// authority key ID
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.authKeyId}">
|
||||
$("#authorityKeyIdentifier").html(parseSerialNumber(authorityKeyIdentifier));
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
$("#authorityKeyIdentifier").html("Not Specified");
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:if test="${not empty initialData.authSerialNumber}">
|
||||
//Convert string to serial String
|
||||
$("#authSerialNumber").html(parseSerialNumber(authoritySerialNumber));
|
||||
</c:if>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.publicKeyValue}">
|
||||
var publicKey = '${initialData.publicKeyValue}';
|
||||
$("#encodedPublicKey").html(parseHexString(publicKey));
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:if test="${not empty initialData.encodedPublicKey}">
|
||||
//Change public key byte to hex
|
||||
var encPublicKey = ${initialData.encodedPublicKey};
|
||||
$("#encodedPublicKey").html(byteToHexString(encPublicKey));
|
||||
</c:if>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:if test="${not empty initialData.subjectKeyIdentifier}">
|
||||
//Change subject byte to hex only for CACertificate
|
||||
if (type === "certificateauthority") {
|
||||
var subjectKeyIdentifier = ${initialData.subjectKeyIdentifier};
|
||||
$("#subjectKeyIdentifier").html(byteToHexString(subjectKeyIdentifier));
|
||||
}
|
||||
</c:if>
|
||||
|
||||
//Initilize tooltips
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
//Vertical alignment on data columns
|
||||
$('.vertical').each(function () {
|
||||
$(this).css({
|
||||
'line-height': $(this).height() + 'px'
|
||||
});
|
||||
});
|
||||
|
||||
//Change link width
|
||||
$("#headingOne, #headingTwo, #headingThree").each(function (e) {
|
||||
var width = $(this).width();
|
||||
//Get link width
|
||||
var linkWidth = $(this).find('a').width();
|
||||
|
||||
//Change width for the link
|
||||
$(this).find('a').css({
|
||||
"padding-right": (width - linkWidth) + "px"
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
|
||||
</my:page>
|
@ -0,0 +1,131 @@
|
||||
<%@page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
|
||||
<%-- JSP TAGS --%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%-- CONTENT --%>
|
||||
<my:page>
|
||||
|
||||
<jsp:attribute name="script">
|
||||
<script type="text/javascript" src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">Issued Certificates</jsp:attribute>
|
||||
<jsp:body>
|
||||
<div class="aca-input-box-header">
|
||||
Issued Credentials
|
||||
<a href="${portal}/certificate-request/issued-certificates/bulk">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download All Issued Certificates">
|
||||
</a>
|
||||
</div>
|
||||
<br />
|
||||
<div class="aca-data-table">
|
||||
<table id="issuedTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2">Hostname</th>
|
||||
<th rowspan="2">Issuer</th>
|
||||
<th rowspan="2">Valid (begin)</th>
|
||||
<th rowspan="2">Valid (end)</th>
|
||||
<th colspan="2">Credentials</th>
|
||||
<th rowspan="2">Options</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Endorsement</th>
|
||||
<th>Platform</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var url = pagePath + '/list';
|
||||
var columns = [
|
||||
{
|
||||
data: 'device.name',
|
||||
render: function (data, type, full, meta) {
|
||||
// if there's a device, display its name, otherwise
|
||||
// display nothing
|
||||
if (full.device) {
|
||||
// TODO render a link to a device details page,
|
||||
// passing the device.id
|
||||
return full.device.name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{data: 'issuer'},
|
||||
{
|
||||
data: 'beginValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatDateTime(data);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'endValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatDateTime(data);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
//Display endorsement credential
|
||||
var html = '';
|
||||
if (full.endorsementCredential !== undefined
|
||||
&& full.endorsementCredential !== null){
|
||||
var id = full.endorsementCredential.id;
|
||||
html += certificateDetailsLink('endorsement', id, false) +' ';
|
||||
}
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
//Display platform credential
|
||||
var html = '';
|
||||
if (full.platformCredentials !== undefined
|
||||
&& full.platformCredentials !== null) {
|
||||
var size = full.platformCredentials.length;
|
||||
|
||||
for(var i = 0; i < size; i++) {
|
||||
var id = full.platformCredentials[i].id;
|
||||
html += certificateDetailsLink('platform', id, false) +' ';
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function(data, type, full, meta) {
|
||||
// set up link to details page
|
||||
var html = '';
|
||||
html += certificateDetailsLink('issued', full.id, true);
|
||||
html += certificateDownloadLink(full.id, pagePath);
|
||||
html += certificateDeleteLink(full.id, pagePath);
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
//Set data tables
|
||||
setDataTables("#issuedTable", url, columns);
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
|
||||
</my:page>
|
@ -0,0 +1,136 @@
|
||||
<%@page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
|
||||
<%-- JSP TAGS --%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%-- CONTENT --%>
|
||||
<my:page>
|
||||
|
||||
<jsp:attribute name="script">
|
||||
<script type="text/javascript" src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">Platform Certificates</jsp:attribute>
|
||||
|
||||
<jsp:body>
|
||||
<!-- text and icon resource variables -->
|
||||
<c:set var="endorsementIcon" value="${icons}/ic_vpn_key_black_24dp.png"/>
|
||||
<div class="aca-input-box-header">
|
||||
<form:form method="POST" action="${portal}/certificate-request/platform-credentials/upload" enctype="multipart/form-data">
|
||||
Platform Credentials
|
||||
<my:file-chooser id="platformCredentialEditor" label="Import Platform Credentials">
|
||||
<input id="importFile" type="file" name="file" multiple="multiple" />
|
||||
</my:file-chooser>
|
||||
<a href="${portal}/certificate-request/platform-credentials/bulk">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download All Platform Certificates">
|
||||
</a>
|
||||
</form:form>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="aca-data-table">
|
||||
<table id="platformTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Device</th>
|
||||
<th>Issuer</th>
|
||||
<th>Type</th>
|
||||
<th>Manufacturer</th>
|
||||
<th>Model</th>
|
||||
<th>Version</th>
|
||||
<th>Board SN</th>
|
||||
<th>Valid (begin)</th>
|
||||
<th>Valid (end)</th>
|
||||
<th>Endorsement</th>
|
||||
<th>Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var url = pagePath +'/list';
|
||||
var columns = [
|
||||
{
|
||||
data: 'device.name',
|
||||
render: function (data, type, full, meta) {
|
||||
// if there's a device, display its name, otherwise
|
||||
// display nothing
|
||||
if (full.device) {
|
||||
// TODO render a link to a device details page,
|
||||
// passing the device.id
|
||||
return full.device.name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{data: 'issuer'},
|
||||
{
|
||||
data: 'credentialType',
|
||||
render: function (data, type, full, meta) {
|
||||
if (full.platformType !== '') {
|
||||
return full.platformType;
|
||||
} else {
|
||||
return full.credentialType;
|
||||
}
|
||||
}
|
||||
},
|
||||
{data: 'manufacturer'},
|
||||
{data: 'model'},
|
||||
{data: 'version'},
|
||||
{data: 'platformSerial'},
|
||||
{
|
||||
data: 'beginValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatDateTime(full.beginValidity);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'endValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatDateTime(full.endValidity);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
//Display endorsement credential
|
||||
if(full.endorsementCredential === null) return '';
|
||||
var html = '';
|
||||
|
||||
var id = full.endorsementCredential.id;
|
||||
html = certificateDetailsLink('endorsement', id, false) +' ';
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function(data, type, full, meta) {
|
||||
// Set up a delete icon with link to handleDeleteRequest().
|
||||
// sets up a hidden input field containing the ID which is
|
||||
// used as a parameter to the REST POST call to delete
|
||||
var html = '';
|
||||
html += certificateDetailsLink('platform', full.id, true);
|
||||
html += certificateDownloadLink(full.id, pagePath);
|
||||
html += certificateDeleteLink(full.id, pagePath);
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
//Set data tables
|
||||
setDataTables("#platformTable", url, columns);
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
</my:page>
|
@ -0,0 +1,78 @@
|
||||
<%@page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
|
||||
<%-- JSP TAGS --%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%-- CONTENT --%>
|
||||
<my:page>
|
||||
|
||||
<jsp:attribute name="script">
|
||||
<script type="text/javascript" src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">Reference Integrity Manifests</jsp:attribute>
|
||||
|
||||
<jsp:body>
|
||||
<!-- text and icon resource variables -->
|
||||
<div class="aca-input-box-header">
|
||||
<form:form method="POST" action="${portal}/reference-manifests/upload" enctype="multipart/form-data">
|
||||
Reference Integrity Manifests
|
||||
<my:file-chooser id="referenceManifestsEditor" label="Import RIMs">
|
||||
<input id="importFile" type="file" name="file" multiple="multiple" />
|
||||
</my:file-chooser>
|
||||
<a href="${portal}/reference-manifests/bulk">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download All RIMs">
|
||||
</a>
|
||||
</form:form>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="aca-data-table">
|
||||
<table id="referenceManifestTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tag ID</th>
|
||||
<th>Type</th>
|
||||
<th>Manufacturer</th>
|
||||
<th>Model</th>
|
||||
<th>Version</th>
|
||||
<th>Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var url = pagePath +'/list';
|
||||
var columns = [
|
||||
{data: 'tagId'},
|
||||
{data: 'rimType'},
|
||||
{data: 'platformManufacturer'},
|
||||
{data: 'platformModel'},
|
||||
{data: 'swidTagVersion'},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function(data, type, full, meta) {
|
||||
// Set up a delete icon with link to handleDeleteRequest().
|
||||
// sets up a hidden input field containing the ID which is
|
||||
// used as a parameter to the REST POST call to delete
|
||||
var html = '';
|
||||
html += rimDetailsLink(full.id);
|
||||
html += rimDownloadLink(full.id, pagePath);
|
||||
html += rimDeleteLink(full.id, pagePath);
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
//Set data tables
|
||||
setDataTables("#referenceManifestTable", url, columns);
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
</my:page>
|
@ -0,0 +1,75 @@
|
||||
<%@page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
|
||||
<%-- JSP TAGS --%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%-- CONTENT --%>
|
||||
<my:page>
|
||||
|
||||
<jsp:attribute name="script">
|
||||
<script type="text/javascript" src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">RIM Database</jsp:attribute>
|
||||
|
||||
<jsp:body>
|
||||
<br/>
|
||||
<div class="aca-data-table">
|
||||
<table id="digestValueTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Manufacturer</th>
|
||||
<th>Model</th>
|
||||
<th>Event Type</th>
|
||||
<th>PCR Index</th>
|
||||
<th>Digest Value</th>
|
||||
<th>Base RIM</th>
|
||||
<th>Support RIM</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var url = pagePath +'/list';
|
||||
var columns = [
|
||||
{data: 'manufacturer',
|
||||
orderable: true,
|
||||
searchable:false},
|
||||
{data: 'model',
|
||||
orderable: false,
|
||||
searchable:false},
|
||||
{data: 'eventType',
|
||||
orderable: false,
|
||||
searchable:false,},
|
||||
{data: 'pcrIndex',
|
||||
orderable: true,
|
||||
searchable:false},
|
||||
{data: 'digestValue',
|
||||
orderable: false,
|
||||
searchable:false},
|
||||
{data: 'baseRimId',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function(data, type, full, meta) {
|
||||
return rimDetailsLink(full.baseRimId);
|
||||
}
|
||||
},
|
||||
{data: 'supportRimId',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function(data, type, full, meta) {
|
||||
return rimDetailsLink(full.supportRimId);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
//Set data tables
|
||||
setDataTables("#digestValueTable", url, columns);
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
</my:page>
|
@ -0,0 +1,653 @@
|
||||
<%@page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
|
||||
<%-- JSP TAGS--%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%--CONTENT--%>
|
||||
<my:page>
|
||||
<jsp:attribute name="style">
|
||||
<link type="text/css" rel="stylesheet" href="${common}/certificate_details.css"/>
|
||||
<link type="text/css" rel="stylesheet" href="${common}/rim_details.css"/>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">
|
||||
<c:choose>
|
||||
<c:when test="${initialData.rimType=='Measurement'}">
|
||||
<c:if test="${initialData.validationResult=='PASS'}">
|
||||
TCG Log events
|
||||
</c:if>
|
||||
<c:if test="${initialData.validationResult=='FAIL'}">
|
||||
TCG Log event(s) not found in the RIM DB
|
||||
</c:if>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${initialData.rimType} Reference Integrity Manifest
|
||||
<a href="${portal}/reference-manifests/download?id=${param.id}">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download ${initialData.rimType} RIM">
|
||||
</a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</jsp:attribute>
|
||||
<jsp:body>
|
||||
<c:set var="passIcon" value="${icons}/ic_checkbox_marked_circle_black_green_24dp.png"/>
|
||||
<c:set var="failIcon" value="${icons}/ic_error_red_24dp.png"/>
|
||||
<c:set var="signatureValidText" value="Signature valid!"/>
|
||||
<c:set var="signatureInvalidText" value="Signature not valid!"/>
|
||||
<c:set var="supportRimHashValidText" value="Support RIM hash valid!"/>
|
||||
<c:set var="supportRimHashInvalidText" value="Support RIM hash not valid!"/>
|
||||
<div id="certificate-details-page" class="container-fluid">
|
||||
<c:choose>
|
||||
<c:when test="${initialData.rimType=='Support' || (initialData.rimType=='Measurement' && initialData.validationResult=='PASS')}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Additional<br />RIM Info</span></div>
|
||||
<div class="col col-md-8">
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.associatedRim}">
|
||||
<a href="${portal}/rim-details?id=${initialData.associatedRim}">
|
||||
${initialData.tagId}
|
||||
</a>
|
||||
<c:if test="${not empty initialData.hostName}">
|
||||
<div>Device: <span>${initialData.hostName}</span></div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.supportId}">
|
||||
<div>Support: <span><a href="${portal}/rim-details?id=${initialData.supportId}">${initialData.supportFilename}</a></span>
|
||||
</div>
|
||||
</c:if>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div class="component col col-md-10" style="color: red; padding-left: 20px">RIM not uploaded from the ACA RIM Page</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
<c:if test="${not initialData.swidBase}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1">
|
||||
<span class="colHeader">RIM Type</span>
|
||||
</div>
|
||||
<div id="baseRim" class="col col-md-8">
|
||||
<c:if test="${initialData.swidCorpus}">
|
||||
<div>SWID Corpus</div>
|
||||
</c:if>
|
||||
<c:if test="${initialData.swidPatch}">
|
||||
<div>SWID Patch</div>
|
||||
</c:if>
|
||||
<c:if test="${initialData.swidSupplemental}">
|
||||
<div>SWID Supplemental</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1">
|
||||
<span class="colRimHeader">
|
||||
<a role="button" data-toggle="collapse" class="collapsed" href="#eventOptions"
|
||||
aria-expanded="true" data-placement="top" aria-controls="eventOptions">
|
||||
Event Summary
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div id="eventsCol" class="col col-md-8">
|
||||
<div id="eventOptions" class="collapse" class="collapsed" aria-expanded="false">
|
||||
<ul>
|
||||
<c:choose>
|
||||
<c:when test="${initialData.rimType=='Support'}">
|
||||
<li>This Support RIM file covers the following critical items:</li>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<li>This Event Log file covers the following critical items:</li>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<ul>
|
||||
<c:if test="${initialData.crtm || initialData.bootManager || initialData.osLoader || initialData.osKernel}">
|
||||
<li>PC Client Boot path</li>
|
||||
</c:if>
|
||||
<ul>
|
||||
<c:if test="${initialData.crtm}">
|
||||
<li>Software Core Root of Trust for Measurement (SRTM)</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.bootManager}">
|
||||
<li>Boot Manager</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.osLoader}">
|
||||
<li>OS Loader</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.osKernel}">
|
||||
<li>OS Kernel</li>
|
||||
</c:if>
|
||||
</ul>
|
||||
<c:if test="${initialData.acpiTables || initialData.smbiosTables || initialData.gptTable || initialData.defaultBootDevice}">
|
||||
<li>Device Configuration</li>
|
||||
</c:if>
|
||||
<ul>
|
||||
<c:if test="${initialData.acpiTables}">
|
||||
<li>ACPI Tables</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.smbiosTables}">
|
||||
<li>SMBIOS Tables</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.gptTable}">
|
||||
<li>GPT Table</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.bootOrder}">
|
||||
<li>Boot Order</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.defaultBootDevice}">
|
||||
<li>Default boot device</li>
|
||||
</c:if>
|
||||
</ul>
|
||||
<c:if test="${initialData.secureBoot || initialData.pk || initialData.kek || initialData.sigDb || initialData.forbiddenDbx}">
|
||||
<li>Secure Boot Variables</li>
|
||||
</c:if>
|
||||
<ul>
|
||||
<c:if test="${initialData.secureBoot}">
|
||||
<li>Secure Boot Enabled</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.pk}">
|
||||
<li>Platform Key (PK)</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.kek}">
|
||||
<li>Key Exchange Key (KEK)</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.sigDb}">
|
||||
<li>Signature Database (db)</li>
|
||||
</c:if>
|
||||
<c:if test="${initialData.forbiddenDbx}">
|
||||
<li>Forbidden Signatures Database (dbx)</li>
|
||||
</c:if>
|
||||
</ul>
|
||||
</ul>
|
||||
</ul>
|
||||
<ul>
|
||||
<c:choose>
|
||||
<c:when test="${initialData.rimType=='Support'}">
|
||||
<li>This Support RIM file covers the following critical items:</li>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<li>This Event Log file covers the following critical items:</li>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<ul>
|
||||
<c:if test="${not initialData.crtm || not initialData.bootManager || not initialData.osLoader || not initialData.osKernel}">
|
||||
<li>PC Client Boot path</li>
|
||||
</c:if>
|
||||
<ul>
|
||||
<c:if test="${not initialData.crtm}">
|
||||
<li>Software Core Root of Trust for Measurement (SRTM)</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.bootManager}">
|
||||
<li>Boot Manager</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.osLoader}">
|
||||
<li>OS Loader</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.osKernel}">
|
||||
<li>OS Kernel</li>
|
||||
</c:if>
|
||||
</ul>
|
||||
<c:if test="${not initialData.acpiTables || not initialData.smbiosTables || not initialData.gptTable || not initialData.bootOrder || not initialData.defaultBootDevice}">
|
||||
<li>Device Configuration</li>
|
||||
</c:if>
|
||||
<ul>
|
||||
<c:if test="${not initialData.acpiTables}">
|
||||
<li>ACPI Tables</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.smbiosTables}">
|
||||
<li>SMBIOS Tables</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.gptTable}">
|
||||
<li>GPT Table</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.bootOrder}">
|
||||
<li>Boot Order</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.defaultBootDevice}">
|
||||
<li>Default boot device</li>
|
||||
</c:if>
|
||||
</ul>
|
||||
<c:if test="${not initialData.secureBoot || not initialData.pk || not initialData.kek || not initialData.sigDb || not initialData.forbiddenDbx}">
|
||||
<li>Secure Boot Variables</li>
|
||||
</c:if>
|
||||
<ul>
|
||||
<c:if test="${not initialData.secureBoot}">
|
||||
<li>Secure Boot Enabled</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.pk}">
|
||||
<li>Platform Key (PK)</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.kek}">
|
||||
<li>Key Exchange Key (KEK)</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.sigDb}">
|
||||
<li>Signature Database (db)</li>
|
||||
</c:if>
|
||||
<c:if test="${not initialData.forbiddenDbx}">
|
||||
<li>Forbidden Signatures Database (dbx)</li>
|
||||
</c:if>
|
||||
</ul>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tableDivTag">
|
||||
<input type="text" id="eventInput" onkeyup="eventSearch(null)" placeholder="Search for text..." /><br />
|
||||
<table id="eventLog">
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Event #</th>
|
||||
<th>PCR Index</th>
|
||||
<th style="width: 20%">Event Type</th>
|
||||
<th>Digest</th>
|
||||
<th style="width: 50%">Event Content</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:if test="${not empty initialData.events}">
|
||||
<c:set var="count" value="1" scope="page"/>
|
||||
<c:forEach items="${initialData.events}" var="event">
|
||||
<c:choose>
|
||||
<c:when test="${event.isError()}">
|
||||
<tr style="background: tomato">
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<tr>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<td style="width: 75px">${count}</td>
|
||||
<td class="pcrCell">PCR${event.getPcrIndex()}</td>
|
||||
<td>${event.getEventTypeStr()}</td>
|
||||
<td class="digestCell">${event.getEventDigestStr()}</td>
|
||||
<td title="${event.getEventContentStr()}"><div style="height: 50px; overflow: auto">${event.getEventContentStr()}</div></td>
|
||||
</tr>
|
||||
<c:set var="count" value="${count + 1}" scope="page"/>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-a col-md-offset-1"><span class="colHeader">${initialData.events.size()} entries</span></div>
|
||||
</c:when>
|
||||
<c:when test="${initialData.rimType=='Measurement' && initialData.validationResult=='FAIL'}">
|
||||
<div style="display: inline">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Base/Support</span></div>
|
||||
<div id="measurements" class="col col-md-8">
|
||||
<div>Download Measurement:
|
||||
<span>
|
||||
<a href="${portal}/reference-manifests/download?id=${param.id}">
|
||||
BIOS Measurements
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<c:if test="${not empty initialData.hostName}">
|
||||
<div>Device: <span>${initialData.hostName}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.tagId}">
|
||||
<div>Base: <span><a href="${portal}/rim-details?id=${initialData.associatedRim}">${initialData.tagId}</a></span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.supportId}">
|
||||
<div>Support: <span><a href="${portal}/rim-details?id=${initialData.supportId}">${initialData.supportFilename}</a></span>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row" style="margin: auto 260px auto 125px">
|
||||
<div class="panel panel-default" style="flex: 1">
|
||||
<div class="panel-heading">Client Log</div>
|
||||
<c:if test="${not empty initialData.livelogEvents}">
|
||||
<c:set var="iterator" value="0" scope="page"/>
|
||||
<c:forEach items="${initialData.livelogEvents}" var="lEvent">
|
||||
<div>
|
||||
<div style="display: flex; background: lightgray;">
|
||||
<div style="display: flex 1; font-weight: bold; margin: auto 1rem auto 1rem">Failed Event Digest:<br />
|
||||
</div>
|
||||
<div style="display: flex 2; margin: 2px auto 2px 25px">
|
||||
<span class="mappedData">PCR Index:</span> ${lEvent.getPcrIndex()}<br />
|
||||
<span class="mappedData">Digest:</span> ${lEvent.getEventDigestStr()}<br />
|
||||
<span class="mappedData">Event Content:</span> ${lEvent.getEventContentStr()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex;">
|
||||
<div class="mappedButton">
|
||||
Expected Events from RIM DB:<br />
|
||||
<span style="word-wrap: break-word"><a role="button" data-toggle="collapse" href="#eventContent${iterator}">${lEvent.getEventTypeString()}</a></span>
|
||||
</div>
|
||||
<div id="eventContent${iterator}" class="panel-collapse collapse in" style="flex: 2">
|
||||
<c:forEach items="${initialData.eventTypeMap}" var="mappedDigest">
|
||||
<c:if test="${mappedDigest.key == lEvent.getEventDigestStr()}">
|
||||
<c:set var="event" value="${mappedDigest.value}" scope="page"/>
|
||||
<c:forEach items="${mappedDigest.value}" var="event">
|
||||
<div class="mappedOverhead">
|
||||
<div><span class="mappedData">PCR Index:</span> ${event.getPcrIndex()}</div>
|
||||
<div><span class="mappedData">Digest:</span> ${event.getEventDigestStr()}</div>
|
||||
<div><span class="mappedData">Event Content:</span> ${event.getEventContentStr()}</div>
|
||||
</div>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</c:forEach>
|
||||
</div>
|
||||
</div>
|
||||
<c:set var="iterator" value="${iterator+1}" scope="page"/>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:when>
|
||||
<c:when test="${initialData.rimType=='Base'}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Software Identity</span></div>
|
||||
<div id="softwareIdentity" class="col col-md-8">
|
||||
<div>SWID Name: <span>${initialData.swidName}</span></div>
|
||||
<div>SWID Version: <span>${initialData.swidVersion}</span></div>
|
||||
<div>SWID Tag ID: <span>${initialData.swidTagId}</span></div>
|
||||
<div>SWID Tag Version: <span>${initialData.swidTagVersion}</span></div>
|
||||
<c:if test="${initialData.swidCorpus}">
|
||||
<div>SWID Corpus: <span><img src="${icons}/ic_checkbox_marked_circle_black_green_24dp.png" title="Corpus Flag"></span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${initialData.swidPatch}">
|
||||
<div>SWID Patch: <span><img src="${icons}/ic_checkbox_marked_circle_black_green_24dp.png" title="Patch Flag"></span>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="${initialData.swidSupplemental}">
|
||||
<div>SWID Supplemental: <span><img src="${icons}/ic_checkbox_marked_circle_black_green_24dp.png" title="Supplemental Flag"></span>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Entity</span></div>
|
||||
<div id="entity" class="col col-md-8">
|
||||
<div>Entity Name: <span>${initialData.entityName}</span></div>
|
||||
<c:if test="${not empty initialData.entityRegId}">
|
||||
<div>Entity Reg ID: <span>${initialData.entityRegId}</span></div>
|
||||
</c:if>
|
||||
<div>Entity Role: <span>${initialData.entityRole}</span></div>
|
||||
<div>Entity Thumbprint: <span>${initialData.entityThumbprint}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Link</span></div>
|
||||
<div id="link" class="col col-md-8">
|
||||
<c:if test="${not empty initialData.linkHref}">
|
||||
<div>
|
||||
<span>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.linkHrefLink}">
|
||||
<a href="${portal}/rim-details?id=${initialData.linkHrefLink}" rel="${initialData.linkRel}">${initialData.linkHref}</a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="${initialData.linkHref}" rel="${initialData.linkRel}">${initialData.linkHref}</a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</div>
|
||||
<div>Rel: <span>${initialData.linkRel}</span>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Meta</span></div>
|
||||
<div id="link" class="col col-md-8">
|
||||
<div>Platform Manufacturer ID: <span>${initialData.platformManufacturerId}</span></div>
|
||||
<div>Platform Manufacturer: <span>${initialData.platformManufacturer}</span></div>
|
||||
<div>Platform Model: <span>${initialData.platformModel}</span></div>
|
||||
<c:if test="${not empty initialData.platformVersion}">
|
||||
<div>Platform Version: <span>${initialData.platformVersion}</span></div>
|
||||
</c:if>
|
||||
<div>Colloquial Version: <span>${initialData.colloquialVersion}</span></div>
|
||||
<div>Edition: <span>${initialData.edition}</span></div>
|
||||
<div>Product: <span>${initialData.product}</span></div>
|
||||
<div>Revision: <span>${initialData.revision}</span></div>
|
||||
|
||||
<c:if test="${not empty initialData.payloadType}">
|
||||
<div>Payload Type: <span>${initialData.payloadType}</span></div>
|
||||
</c:if>
|
||||
<div>Binding Spec: <span>${initialData.bindingSpec}</span></div>
|
||||
<div>Binding Spec Version: <span>${initialData.bindingSpecVersion}</span></div>
|
||||
<c:if test="${not empty initialData.pcUriGlobal}">
|
||||
<div>PC URI Global: <span>${initialData.pcUriGlobal}</span></div>
|
||||
</c:if>
|
||||
<c:if test="${not empty initialData.pcUriLocal}">
|
||||
<div>PC URI Local: <span>${initialData.pcUriLocal}</span></div>
|
||||
</c:if>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.rimLinkId}">
|
||||
<div>Rim Link Hash: <span><a href="${portal}/rim-details?id=${initialData.rimLinkId}">${initialData.rimLinkHash}</a></span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<div>Rim Link Hash: <span>${initialData.rimLinkHash}</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<c:if test="${not empty initialData.rimLinkHash}">
|
||||
<span>
|
||||
<c:choose>
|
||||
<c:when test="${initialData.linkHashValid}">
|
||||
<img src="${passIcon}" title="SWID Tag exist.">
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<img src="${failIcon}" title="SWID Tag doesn't exist.">
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Payload/Support RIM(s)</span></div>
|
||||
<div id="platformConfiguration" class="col col-md-8">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" id="headingOne">
|
||||
<h4 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#platformConfiguration" class="collapsed"
|
||||
href="#directorycollapse" aria-expanded="true" aria-controls="directorycollapse">
|
||||
Directory
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="directorycollapse" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne" aria-expanded="true">
|
||||
<div class="panel-body">
|
||||
<div class="panel-heading" role="tab" id="headingThree">
|
||||
<h3 class="panel-title">
|
||||
<a role="button" data-toggle="collapse" data-parent="#directorycollapse" class="collapsed"
|
||||
href="#filescollapse" aria-expanded="false" aria-controls="filescollapse">
|
||||
Files
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div id="filescollapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree" aria-expanded="true">
|
||||
<c:if test="${not empty initialData.swidFiles}">
|
||||
<div id="componentIdentifier" class="row">
|
||||
<c:forEach items="${initialData.swidFiles}" var="resource">
|
||||
<div class="component col col-md-10" style="padding-left: 20px">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span data-toggle="tooltip" data-placement="top" title="Resource File">
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.associatedRim}">
|
||||
<a href="${portal}/rim-details?id=${initialData.associatedRim}">${resource.getName()}</a>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.supportRimHashValid}">
|
||||
<img src="${passIcon}" title="${supportRimHashValidText}"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<img src="${failIcon}" title="${supportRimHashInvalidText}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${resource.getName()}
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</div>
|
||||
<div class="component col col-md-10">
|
||||
<span class="fieldHeader">File Size:</span>
|
||||
<span class="fieldValue">${resource.getSize()}</span><br/>
|
||||
<span class="fieldHeader">Hash:</span>
|
||||
<span class="fieldValue" style="overflow-wrap: break-word">${resource.getHashValue()}</span><br/>
|
||||
<c:if test="${not empty resource.getRimFormat()}">
|
||||
<span class="fieldHeader">RIM Format:</span>
|
||||
<span class="fieldValue">${resource.getRimFormat()}</span><br/>
|
||||
</c:if>
|
||||
<c:if test="${not empty resource.getRimType()}">
|
||||
<span class="fieldHeader">RIM Type:</span>
|
||||
<span class="fieldValue">${resource.getRimType()}</span><br/>
|
||||
</c:if>
|
||||
<c:if test="${not empty resource.getRimUriGlobal()}">
|
||||
<span class="fieldHeader">URI Global:</span>
|
||||
<span class="fieldValue">${resource.getRimUriGlobal()}</span><br/>
|
||||
</c:if>
|
||||
</div>
|
||||
<c:choose>
|
||||
<c:when test="${not empty initialData.pcrList}">
|
||||
<div class="component col col-md-10">
|
||||
<div class="panel-body">
|
||||
<div class="component" role="tab" id="pcrValues">
|
||||
<a role="button" data-toggle="collapse" data-parent="#directorycollapse" class="collapsed"
|
||||
href="#pcrscollapse" aria-expanded="false" aria-controls="pcrscollapse">
|
||||
Expected PCR Values
|
||||
</a>
|
||||
</div>
|
||||
<div id="pcrscollapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree" aria-expanded="true">
|
||||
<div>
|
||||
<c:set var="count" value="0" scope="page"/>
|
||||
<c:forEach items="${initialData.pcrList}" var="pcrValue">
|
||||
<div id="componentIdentifier" class="row">
|
||||
<div>
|
||||
<span>PCR ${count} - </span>
|
||||
<span style="overflow-wrap: break-word">${pcrValue}</span>
|
||||
</div>
|
||||
</div>
|
||||
<c:set var="count" value="${count + 1}" scope="page"/>
|
||||
</c:forEach>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:if test="${not initialData.swidPatch and not initialData.swidSupplemental}">
|
||||
<div class="component col col-md-10" style="color: red; padding-left: 20px">Support RIM file named ${resource.getName()} was not imported via the Reference Integrity Manifest page.</div>
|
||||
</c:if>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:forEach>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1 col-md-offset-1"><span class="colHeader">Signature</span></div>
|
||||
<div id="signature" class="col col-md-8">
|
||||
<div>Validity: <span>
|
||||
<c:choose>
|
||||
<c:when test="${initialData.signatureValid}">
|
||||
<img src="${passIcon}" title="${signatureValidText}"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<img src="${failIcon}" title="${signatureInvalidText}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
<c:if test="${not empty initialData.issuerID}">
|
||||
<div><a href="${portal}/certificate-details?id=${initialData.issuerID}&type=certificateauthority">Signing certificate</a></div>
|
||||
</c:if>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
<c:if test="${not empty initialData.skID}">
|
||||
<div>Subject Key Identifier: ${initialData.skID}</div>
|
||||
</c:if>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function eventSearch(txtInput) {
|
||||
// Declare variables
|
||||
var input, filter, table, tr, td, i, txtValue, txtFound;
|
||||
|
||||
if (txtInput === null) {
|
||||
input = document.getElementById("eventInput");
|
||||
filter = input.value.toUpperCase();
|
||||
} else {
|
||||
filter = txtInput;
|
||||
}
|
||||
|
||||
table = document.getElementById("eventLog");
|
||||
tr = table.getElementsByTagName("tr");
|
||||
|
||||
// Loop through all table rows, and hide those who don't match the search query
|
||||
for (i = 0; i < tr.length; i++) {
|
||||
txtFound = true;
|
||||
tds = tr[i].getElementsByTagName("td");
|
||||
for (j = 0; j < tds.length; j++) {
|
||||
td = tds[j];
|
||||
|
||||
if (td) {
|
||||
txtValue = td.textContent || td.innerText;
|
||||
if (txtValue.toUpperCase().indexOf(filter) > -1) {
|
||||
txtFound = true;
|
||||
break;
|
||||
} else {
|
||||
txtFound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (txtFound) {
|
||||
tr[i].style.display = "";
|
||||
} else {
|
||||
tr[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
window.onload = function () {
|
||||
// Constant retrieved from server-side via JSP
|
||||
var maxRows = 11;
|
||||
|
||||
var table = document.getElementById('eventLog');
|
||||
var wrapper = table.parentNode;
|
||||
var rowsInTable = table.rows.length;
|
||||
var height = 0;
|
||||
if (rowsInTable > maxRows) {
|
||||
for (var i = 0; i < maxRows; i++) {
|
||||
height += table.rows[i].clientHeight;
|
||||
}
|
||||
wrapper.style.height = height + "px";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</jsp:body>
|
||||
</my:page>
|
@ -0,0 +1,155 @@
|
||||
<%@page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
|
||||
<%-- JSP TAGS --%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%-- CONTENT --%>
|
||||
<my:page>
|
||||
<jsp:attribute name="script">
|
||||
<script type="text/javascript" src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">Trust Chain Management</jsp:attribute>
|
||||
|
||||
<jsp:body>
|
||||
<span class="aca-input-box-header">
|
||||
HIRS Attestation CA Certificate
|
||||
</span>
|
||||
<my:details-viewer id="aca-cert-viewer" label="HIRS Attestation CA Certificate">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-md-offset-1"><span class="colHeader">Issuer</span></div>
|
||||
<div id="issuer" class="col col-md-8">
|
||||
<!-- Display the issuer, and provide a link to the issuer details if provided -->
|
||||
<c:choose>
|
||||
<c:when test="${not empty acaCertData.issuerID}">
|
||||
<a href="${portal}/certificate-details?id=${acaCertData.issuerID}&type=certificateauthority">
|
||||
${acaCertData.issuer}
|
||||
</a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${acaCertData.issuer}
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
<c:if test="${not empty acaCertData.subject}">
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-md-offset-1"><span class="colHeader">Subject</span></div>
|
||||
<div id="subject" class="col col-md-8">${acaCertData.subject}</div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-md-offset-1"><span class="colHeader">Serial Number</span></div>
|
||||
<div id="serialNumber" class="col col-md-8">${acaCertData.serialNumber}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-md-offset-1"><span class="colHeader">Validity</span></div>
|
||||
<div id="validity" class="col col-md-8">
|
||||
<div>Not Before: <span>${acaCertData.beginValidity}</span></div>
|
||||
<div>Not After: <span>${acaCertData.endValidity}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-md-offset-1"><span class="colHeader">Signature</span></div>
|
||||
<div id="signature" class="col col-md-8"></div>
|
||||
</div>
|
||||
<c:if test="${not empty acaCertData.encodedPublicKey}">
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-md-offset-1"><span class="colHeader">Public Key</span></div>
|
||||
<div id="encodedPublicKey" class="col col-md-8"></div>
|
||||
</div>
|
||||
</c:if>
|
||||
<div class="spacer"></div>
|
||||
</div>
|
||||
</my:details-viewer>
|
||||
|
||||
<a href="${portal}/certificate-request/trust-chain/download-aca-cert">
|
||||
<img src="${baseURL}/images/icons/ic_file_download_black_24dp.png" title="Download ACA Certificate">
|
||||
</a>
|
||||
<div class="aca-input-box-header">
|
||||
<form:form method="POST" action="${portal}/certificate-request/trust-chain/upload" enctype="multipart/form-data">
|
||||
Trust Chain CA Certificates
|
||||
<my:file-chooser id="tc-editor" label="Import Trust Chain Certificates">
|
||||
<input id="importFile" type="file" name="file" multiple="multiple" />
|
||||
</my:file-chooser>
|
||||
<a href="${portal}/certificate-request/trust-chain/bulk">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download All Trust Chain Certificates">
|
||||
</a>
|
||||
</form:form>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="aca-data-table">
|
||||
<table id="trustChainTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Issuer</th>
|
||||
<th>Subject</th>
|
||||
<th>Valid (begin)</th>
|
||||
<th>Valid (end)</th>
|
||||
<th>Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var url = pagePath +'/list';
|
||||
var signature = ${acaCertData.signature};
|
||||
|
||||
//Format validity time
|
||||
$("#validity span").each(function(){
|
||||
$(this).text(formatDateTime($(this).text()));
|
||||
});
|
||||
|
||||
//Convert byte array to string
|
||||
$("#signature").html(byteToHexString(signature));
|
||||
|
||||
<c:if test="${not empty acaCertData.encodedPublicKey}">
|
||||
//Change publick key byte to hex
|
||||
var publicKey = ${acaCertData.encodedPublicKey};
|
||||
$("#encodedPublicKey").html(byteToHexString(publicKey));
|
||||
</c:if>
|
||||
|
||||
var columns = [
|
||||
{data: 'issuer'},
|
||||
{data: 'subject'},
|
||||
{
|
||||
data: 'beginValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatDateTime(full.beginValidity);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'endValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatDateTime(full.endValidity);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function(data, type, full, meta) {
|
||||
// Set up a delete icon with link to handleDeleteRequest().
|
||||
// sets up a hidden input field containing the ID which is
|
||||
// used as a parameter to the REST POST call to delete
|
||||
var html = '';
|
||||
html += certificateDetailsLink('certificateauthority', full.id, true);
|
||||
html += certificateDownloadLink(full.id, pagePath);
|
||||
html += certificateDeleteLink(full.id, pagePath);
|
||||
return html;
|
||||
}
|
||||
}
|
||||
];
|
||||
//Set data tables
|
||||
setDataTables("#trustChainTable", url, columns);
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
|
||||
</my:page>
|
@ -0,0 +1,256 @@
|
||||
<%@page contentType="text/html" pageEncoding="UTF-8"%>
|
||||
|
||||
<%-- JSP TAGS --%>
|
||||
<%@taglib prefix="c" uri="jakarta.tags.core" %>
|
||||
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
|
||||
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
|
||||
|
||||
<%-- CONTENT --%>
|
||||
<my:page>
|
||||
|
||||
<jsp:attribute name="script">
|
||||
<script type="text/javascript" src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">Validation Reports</jsp:attribute>
|
||||
|
||||
<jsp:body>
|
||||
<!-- text and icon resource variables -->
|
||||
<c:set var="passIcon" value="${icons}/ic_checkbox_marked_circle_black_green_24dp.png"/>
|
||||
<c:set var="failIcon" value="${icons}/ic_error_red_24dp.png"/>
|
||||
<c:set var="errorIcon" value="${icons}/ic_error_black_24dp.png"/>
|
||||
<c:set var="unknownIcon" value="${icons}/ic_questionmark_circle_orange_24dp.png"/>
|
||||
<c:set var="passText" value="Validation Passed"/>
|
||||
<c:set var="failText" value="Validation Failed"/>
|
||||
<c:set var="errorText" value="Validation Error"/>
|
||||
<c:set var="unknownText" value="Unknown Validation Status"/>
|
||||
|
||||
<form:form id="download" method="POST" action="${portal}/validation-reports/download">
|
||||
Download Validation Reports
|
||||
<my:download-info id="validationReportsDownload" label="Download Validation Reports">
|
||||
<label>Company<input id="company" type="text" pattern="^\w*$"
|
||||
title="Letters, numbers, and spaces only" name="company" /></label>
|
||||
<label>Contract #<input id="contract" type="text" pattern="^\w*$"
|
||||
title="Letters, numbers, and spaces only" name="contract" /></label>
|
||||
<br>
|
||||
<label>Date range start<input id="dateStart" type="date" name="dateStart" /></label>
|
||||
<label>Date range end<input id="dateEnd" type="date" name="dateEnd" /></label>
|
||||
</my:download-info>
|
||||
</form:form>
|
||||
|
||||
<div class="aca-data-table">
|
||||
<table id="reportTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2">Result</th>
|
||||
<th rowspan="2">Timestamp</th>
|
||||
<th rowspan="2">Device</th>
|
||||
<th colspan="3">Credential Validations</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="text-align:center">Endorsement</th>
|
||||
<th style="text-align:center">Platform</th>
|
||||
<th style="text-align:center">Firmware</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
var url = portal + '/validation-reports/list';
|
||||
var columns = [
|
||||
{
|
||||
data: 'overallValidationResult',
|
||||
searchable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
var html = '';
|
||||
var unknownStatus = '<img class="icon" src="${unknownIcon}" title="${unknownText}"/>';
|
||||
|
||||
// create status icon
|
||||
var result = full.overallValidationResult;
|
||||
var ovallMessage = full.message;
|
||||
if (result) {
|
||||
switch (result) {
|
||||
case "PASS":
|
||||
html += '<img src="${passIcon}" title="${passText}"/>';
|
||||
break;
|
||||
case "FAIL":
|
||||
html += '<img src="${failIcon}" title="' + ovallMessage + '"/>';
|
||||
break;
|
||||
case "ERROR":
|
||||
html += '<img src="${errorIcon}" title="' + ovallMessage + '"/>';
|
||||
break;
|
||||
default:
|
||||
html += unknownStatus;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
html += unknownStatus;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
// Note: DB column is create_time, while the
|
||||
// JSON property / java property is createTime. Need to sort
|
||||
// on the field createTime, but the column's
|
||||
// date source is create_time.
|
||||
data: 'create_time',
|
||||
name: 'createTime',
|
||||
searchable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatDateTime(full.createTime);
|
||||
}
|
||||
},
|
||||
{
|
||||
// TODO render a link to a device details page,
|
||||
// passing the device.id
|
||||
data: 'device.name'
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return getValidationDisplayHtml(full, "ENDORSEMENT_CREDENTIAL")
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return getValidationDisplayHtml(full, "PLATFORM_CREDENTIAL")
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return getValidationDisplayHtml(full, "FIRMWARE")
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
//Set data tables
|
||||
var dataTable = setDataTables("#reportTable", url, columns);
|
||||
dataTable.order([1, 'desc']).draw(); //order by createTime
|
||||
});
|
||||
|
||||
$("#download").submit(function(e) {
|
||||
var tableLength = $("#reportTable").rows;
|
||||
var createTimes = "";
|
||||
var deviceNames = "";
|
||||
$('#reportTable tr').not('thead tr').each(function() {
|
||||
createTimes += $(this).find("td").eq(1).html() + ",";
|
||||
deviceNames += $(this).find("td").eq(2).html() + ",";
|
||||
});
|
||||
createTimes = createTimes.substring(0, createTimes.length - 1);
|
||||
deviceNames = deviceNames.substring(0, deviceNames.length - 1);
|
||||
var params = [
|
||||
{
|
||||
name: 'createTimes',
|
||||
value: createTimes
|
||||
},
|
||||
{
|
||||
name: 'deviceNames',
|
||||
value: deviceNames
|
||||
}
|
||||
];
|
||||
$(this).append($.map(params, function(param) {
|
||||
return $('<input>', {
|
||||
type: 'hidden',
|
||||
name: param.name,
|
||||
value: param.value
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
$(".btn-primary").click(function() {
|
||||
$("#validationReportsDownload").modal('hide');
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets HTML to display (icon tag) for the specified validation type.
|
||||
* If a validation for the requested type is not found, an empty
|
||||
* string is returned (and no icon will be displayed).
|
||||
*/
|
||||
function getValidationDisplayHtml(full, validation_type) {
|
||||
var html = '';
|
||||
// loop through all the validations, looking for the one matching
|
||||
// the validation_type.
|
||||
for (var i = 0; i < full.validations.length; i++) {
|
||||
var curValidation = full.validations[i];
|
||||
var curResult = curValidation.result;
|
||||
var curMessage = curValidation.message;
|
||||
|
||||
if (curValidation.validationType === validation_type) {
|
||||
var unknownStatus = '<img class="icon" src="${unknownIcon}" title="${unknownText}"/>';
|
||||
|
||||
// display appropriate icon based on result
|
||||
if (curResult) {
|
||||
|
||||
// if this validation is associated with a certificate,
|
||||
// link to the details page
|
||||
if (curValidation.certificatesUsed.length > 0) {
|
||||
var certType = '';
|
||||
switch (validation_type) {
|
||||
case "PLATFORM_CREDENTIAL":
|
||||
case "PLATFORM_CREDENTIAL_ATTRIBUTES":
|
||||
certType = "platform";
|
||||
break;
|
||||
case "ENDORSEMENT_CREDENTIAL":
|
||||
certType = "endorsement";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (validation_type) {
|
||||
case "PLATFORM_CREDENTIAL":
|
||||
case "PLATFORM_CREDENTIAL_ATTRIBUTES":
|
||||
case "ENDORSEMENT_CREDENTIAL":
|
||||
html += '<a href="${portal}/certificate-details?id='
|
||||
+ curValidation.certificatesUsed[0].id
|
||||
+ '&type=' + certType + '">';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (validation_type) {
|
||||
case "FIRMWARE":
|
||||
html += '<a href="${portal}/rim-details?id='
|
||||
+ curValidation.rimId + '">';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (curResult) {
|
||||
case "PASS":
|
||||
html += '<img src="${passIcon}" title="' + curMessage + '"/>';
|
||||
break;
|
||||
case "FAIL":
|
||||
html += '<img src="${failIcon}" title="' + curMessage + '"/>';
|
||||
break;
|
||||
case "ERROR":
|
||||
html += '<img src="${errorIcon}" title="' + curMessage + '"/>';
|
||||
break;
|
||||
default:
|
||||
html += unknownStatus;
|
||||
break;
|
||||
}
|
||||
|
||||
// add closing tag for href tag if needed.
|
||||
if (curValidation.certificatesUsed.length > 0 || curValidation.rimId !== "") {
|
||||
html += '</a>';
|
||||
}
|
||||
} else {
|
||||
html += unknownStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
return html;
|
||||
}
|
||||
</script>
|
||||
</jsp:body>
|
||||
|
||||
</my:page>
|
1345
HIRS_Utils/src/main/resources/swid_schema.xsd
Normal file
1345
HIRS_Utils/src/main/resources/swid_schema.xsd
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user