mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-30 01:39:05 +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.Column;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.GenerationType;
|
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.MappedSuperclass;
|
import jakarta.persistence.MappedSuperclass;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.hibernate.annotations.ColumnDefault;
|
import org.hibernate.annotations.ColumnDefault;
|
||||||
import org.hibernate.annotations.Generated;
|
import org.hibernate.annotations.Generated;
|
||||||
import org.hibernate.annotations.GenerationTime;
|
import org.hibernate.annotations.GenerationTime;
|
||||||
import org.hibernate.annotations.JdbcTypeCode;
|
import org.hibernate.annotations.UuidGenerator;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -19,6 +19,7 @@ import java.util.UUID;
|
|||||||
/**
|
/**
|
||||||
* An abstract database entity.
|
* An abstract database entity.
|
||||||
*/
|
*/
|
||||||
|
@EqualsAndHashCode
|
||||||
@ToString
|
@ToString
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public abstract class AbstractEntity implements Serializable {
|
public abstract class AbstractEntity implements Serializable {
|
||||||
@ -31,8 +32,8 @@ public abstract class AbstractEntity implements Serializable {
|
|||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "id")
|
@Column(name = "id")
|
||||||
@GeneratedValue(generator = "uuid2", strategy=GenerationType.AUTO)
|
@UuidGenerator(style = UuidGenerator.Style.AUTO)
|
||||||
@JdbcTypeCode(java.sql.Types.VARCHAR)
|
@GeneratedValue
|
||||||
@Getter
|
@Getter
|
||||||
private UUID id;
|
private UUID id;
|
||||||
|
|
||||||
@ -75,26 +76,4 @@ public abstract class AbstractEntity implements Serializable {
|
|||||||
public void resetCreateTime() {
|
public void resetCreateTime() {
|
||||||
createTime.setTime(new Date().getTime());
|
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 jakarta.persistence.MappedSuperclass;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import org.hibernate.annotations.JdbcTypeCode;
|
||||||
|
import org.hibernate.type.SqlTypes;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ public abstract class ArchivableEntity extends AbstractEntity {
|
|||||||
@Column(name = "archived_time")
|
@Column(name = "archived_time")
|
||||||
private Date archivedTime;
|
private Date archivedTime;
|
||||||
|
|
||||||
|
@JdbcTypeCode(SqlTypes.LONGVARCHAR)
|
||||||
@Column(name = "archived_description")
|
@Column(name = "archived_description")
|
||||||
private String archivedDescription;
|
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.Entity;
|
||||||
import jakarta.persistence.Transient;
|
import jakarta.persistence.Transient;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.bouncycastle.asn1.ASN1BitString;
|
import org.bouncycastle.asn1.ASN1BitString;
|
||||||
import org.bouncycastle.asn1.ASN1Encodable;
|
import org.bouncycastle.asn1.ASN1Encodable;
|
||||||
import org.bouncycastle.asn1.ASN1GeneralizedTime;
|
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
|
* It stores certain attributes separately from the serialized certificate to enable querying on
|
||||||
* those attributes.
|
* those attributes.
|
||||||
*/
|
*/
|
||||||
|
@Log4j2
|
||||||
@Entity
|
@Entity
|
||||||
public abstract class Certificate extends ArchivableEntity {
|
public abstract class Certificate extends ArchivableEntity {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(Certificate.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the different certificate types.
|
* Holds the different certificate types.
|
||||||
*/
|
*/
|
||||||
@ -561,8 +559,8 @@ public abstract class Certificate extends ArchivableEntity {
|
|||||||
try {
|
try {
|
||||||
return getX509Certificate().getVersion() - 1;
|
return getX509Certificate().getVersion() - 1;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.warn("X509 Credential Version not found.");
|
log.warn("X509 Credential Version not found.");
|
||||||
LOGGER.error(ex);
|
log.error(ex);
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +587,7 @@ public abstract class Certificate extends ArchivableEntity {
|
|||||||
isIssuer = "";
|
isIssuer = "";
|
||||||
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException
|
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException
|
||||||
| NoSuchProviderException | SignatureException e) {
|
| NoSuchProviderException | SignatureException e) {
|
||||||
LOGGER.error(e);
|
log.error(e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ATTRIBUTE_CERTIFICATE:
|
case ATTRIBUTE_CERTIFICATE:
|
||||||
@ -604,7 +602,7 @@ public abstract class Certificate extends ArchivableEntity {
|
|||||||
} catch (NoSuchAlgorithmException
|
} catch (NoSuchAlgorithmException
|
||||||
| InvalidKeyException
|
| InvalidKeyException
|
||||||
| SignatureException sigEx) {
|
| SignatureException sigEx) {
|
||||||
LOGGER.error(sigEx);
|
log.error(sigEx);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -769,7 +767,7 @@ public abstract class Certificate extends ArchivableEntity {
|
|||||||
asn1InputStream = new ASN1InputStream(oct.getOctets());
|
asn1InputStream = new ASN1InputStream(oct.getOctets());
|
||||||
asn1Primitive = asn1InputStream.readObject();
|
asn1Primitive = asn1InputStream.readObject();
|
||||||
} catch (IOException ioEx) {
|
} catch (IOException ioEx) {
|
||||||
LOGGER.error(ioEx);
|
log.error(ioEx);
|
||||||
} finally {
|
} finally {
|
||||||
if (asn1InputStream != null) {
|
if (asn1InputStream != null) {
|
||||||
asn1InputStream.close();
|
asn1InputStream.close();
|
||||||
@ -794,7 +792,7 @@ public abstract class Certificate extends ArchivableEntity {
|
|||||||
.getInstance(JcaX509ExtensionUtils.parseExtensionValue(authInfoAccess))));
|
.getInstance(JcaX509ExtensionUtils.parseExtensionValue(authInfoAccess))));
|
||||||
}
|
}
|
||||||
} catch (IOException ioEx) {
|
} catch (IOException ioEx) {
|
||||||
LOGGER.error(ioEx);
|
log.error(ioEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
@ -993,7 +991,7 @@ public abstract class Certificate extends ArchivableEntity {
|
|||||||
certificateHolder.getSubjectPublicKeyInfo().parsePublicKey().toASN1Primitive()
|
certificateHolder.getSubjectPublicKeyInfo().parsePublicKey().toASN1Primitive()
|
||||||
);
|
);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.info("No RSA Key Detected in certificate");
|
log.info("No RSA Key Detected in certificate");
|
||||||
return null;
|
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;
|
private String platformModel = null;
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String fileName = null;
|
private String fileName = null;
|
||||||
// @Type(type="uuid-char")
|
|
||||||
@JdbcTypeCode(java.sql.Types.VARCHAR)
|
@JdbcTypeCode(java.sql.Types.VARCHAR)
|
||||||
@Column
|
@Column
|
||||||
private UUID associatedRim;
|
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;
|
package hirs.attestationca.persist.entity.userdefined.certificate;
|
||||||
|
|
||||||
import 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.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -44,6 +46,43 @@ public class CertificateAuthorityCredential extends Certificate {
|
|||||||
@Column
|
@Column
|
||||||
private final String credentialType = "TCPA Trusted Platform Module Endorsement";
|
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
|
* Construct a new CertificateAuthorityCredential given its binary contents. The given
|
||||||
* certificate should represent either an X509 certificate or X509 attribute certificate.
|
* 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.TBBSecurityAssertion;
|
||||||
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference;
|
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference;
|
||||||
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2;
|
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2;
|
||||||
|
import hirs.attestationca.persist.service.CertificateService;
|
||||||
|
import hirs.attestationca.persist.service.selector.CertificateSelector;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Transient;
|
import jakarta.persistence.Transient;
|
||||||
@ -46,6 +48,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class persists Platform credentials by extending the base Certificate
|
* This class persists Platform credentials by extending the base Certificate
|
||||||
@ -94,7 +97,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
|||||||
* TCG Platform Specification values
|
* TCG Platform Specification values
|
||||||
* At this time these are placeholder 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("#00000000", "Unclassified");
|
||||||
put("#00000001", "PC Client");
|
put("#00000001", "PC Client");
|
||||||
put("#00000002", "PDA");
|
put("#00000002", "PDA");
|
||||||
@ -128,89 +131,89 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
|||||||
/**
|
/**
|
||||||
* This class enables the retrieval of PlatformCredentials by their attributes.
|
* This class enables the retrieval of PlatformCredentials by their attributes.
|
||||||
*/
|
*/
|
||||||
// public static class Selector extends CertificateSelector<PlatformCredential> {
|
public static class Selector extends CertificateSelector<PlatformCredential> {
|
||||||
// /**
|
/**
|
||||||
// * Construct a new CertificateSelector that will use the given {@link CertificateManager} to
|
* Construct a new CertificateSelector that will use the given {@link CertificateService} to
|
||||||
// * retrieve one or many PlatformCredentials.
|
* retrieve one or many PlatformCredentials.
|
||||||
// *
|
*
|
||||||
// * @param certificateManager the certificate manager to be used to retrieve certificates
|
* @param certificateManager the certificate manager to be used to retrieve certificates
|
||||||
// */
|
*/
|
||||||
// public Selector(final CertificateManager certificateManager) {
|
public Selector(final CertificateService certificateManager) {
|
||||||
// super(certificateManager, PlatformCredential.class);
|
super(certificateManager, PlatformCredential.class);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Specify a manufacturer that certificates must have to be considered as matching.
|
* Specify a manufacturer that certificates must have to be considered as matching.
|
||||||
// * @param manufacturer the manufacturer to query, not empty or null
|
* @param manufacturer the manufacturer to query, not empty or null
|
||||||
// * @return this instance (for chaining further calls)
|
* @return this instance (for chaining further calls)
|
||||||
// */
|
*/
|
||||||
// public Selector byManufacturer(final String manufacturer) {
|
public Selector byManufacturer(final String manufacturer) {
|
||||||
// setFieldValue(MANUFACTURER_FIELD, manufacturer);
|
setFieldValue(MANUFACTURER_FIELD, manufacturer);
|
||||||
// return this;
|
return this;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Specify a model that certificates must have to be considered as matching.
|
* Specify a model that certificates must have to be considered as matching.
|
||||||
// * @param model the model to query, not empty or null
|
* @param model the model to query, not empty or null
|
||||||
// * @return this instance (for chaining further calls)
|
* @return this instance (for chaining further calls)
|
||||||
// */
|
*/
|
||||||
// public Selector byModel(final String model) {
|
public Selector byModel(final String model) {
|
||||||
// setFieldValue(MODEL_FIELD, model);
|
setFieldValue(MODEL_FIELD, model);
|
||||||
// return this;
|
return this;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Specify a version that certificates must have to be considered as matching.
|
* Specify a version that certificates must have to be considered as matching.
|
||||||
// * @param version the version to query, not empty or null
|
* @param version the version to query, not empty or null
|
||||||
// * @return this instance (for chaining further calls)
|
* @return this instance (for chaining further calls)
|
||||||
// */
|
*/
|
||||||
// public Selector byVersion(final String version) {
|
public Selector byVersion(final String version) {
|
||||||
// setFieldValue(VERSION_FIELD, version);
|
setFieldValue(VERSION_FIELD, version);
|
||||||
// return this;
|
return this;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Specify a serial number that certificates must have to be considered as matching.
|
* Specify a serial number that certificates must have to be considered as matching.
|
||||||
// * @param serialNumber the serial number to query, not empty or null
|
* @param serialNumber the serial number to query, not empty or null
|
||||||
// * @return this instance (for chaining further calls)
|
* @return this instance (for chaining further calls)
|
||||||
// */
|
*/
|
||||||
// public Selector bySerialNumber(final String serialNumber) {
|
public Selector bySerialNumber(final String serialNumber) {
|
||||||
// setFieldValue(SERIAL_NUMBER_FIELD, serialNumber);
|
setFieldValue(SERIAL_NUMBER_FIELD, serialNumber);
|
||||||
// return this;
|
return this;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Specify a board serial number that certificates must have to be considered as matching.
|
* 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
|
* @param boardSerialNumber the board serial number to query, not empty or null
|
||||||
// * @return this instance (for chaining further calls)
|
* @return this instance (for chaining further calls)
|
||||||
// */
|
*/
|
||||||
// public Selector byBoardSerialNumber(final String boardSerialNumber) {
|
public Selector byBoardSerialNumber(final String boardSerialNumber) {
|
||||||
// setFieldValue(PLATFORM_SERIAL_FIELD, boardSerialNumber);
|
setFieldValue(PLATFORM_SERIAL_FIELD, boardSerialNumber);
|
||||||
// return this;
|
return this;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Specify a chassis serial number that certificates must have to be considered as matching.
|
* 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
|
* @param chassisSerialNumber the board serial number to query, not empty or null
|
||||||
// * @return this instance (for chaining further calls)
|
* @return this instance (for chaining further calls)
|
||||||
// */
|
*/
|
||||||
// public Selector byChassisSerialNumber(final String chassisSerialNumber) {
|
public Selector byChassisSerialNumber(final String chassisSerialNumber) {
|
||||||
// setFieldValue(CHASSIS_SERIAL_NUMBER_FIELD, chassisSerialNumber);
|
setFieldValue(CHASSIS_SERIAL_NUMBER_FIELD, chassisSerialNumber);
|
||||||
// return this;
|
return this;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// /**
|
/**
|
||||||
// * Specify a device id that certificates must have to be considered
|
* Specify a device id that certificates must have to be considered
|
||||||
// * as matching.
|
* as matching.
|
||||||
// *
|
*
|
||||||
// * @param device the device id to query
|
* @param device the device id to query
|
||||||
// * @return this instance (for chaining further calls)
|
* @return this instance (for chaining further calls)
|
||||||
// */
|
*/
|
||||||
// public Selector byDeviceId(final UUID device) {
|
public Selector byDeviceId(final UUID device) {
|
||||||
// setFieldValue(DEVICE_ID_FIELD, device);
|
setFieldValue(DEVICE_ID_FIELD, device);
|
||||||
// return this;
|
return this;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
private String credentialType = null;
|
private String credentialType = null;
|
||||||
@ -275,9 +278,9 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
|||||||
* @param certMan the CertificateManager to be used to retrieve persisted certificates
|
* @param certMan the CertificateManager to be used to retrieve persisted certificates
|
||||||
* @return a PlatformCredential.Selector instance to use for retrieving certificates
|
* @return a PlatformCredential.Selector instance to use for retrieving certificates
|
||||||
*/
|
*/
|
||||||
// public static Selector select(final CertificateManager certMan) {
|
public static Selector select(final CertificateService certMan) {
|
||||||
// return new Selector(certMan);
|
return new Selector(certMan);
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new PlatformCredential given its binary contents. ParseFields is
|
* Construct a new PlatformCredential given its binary contents. ParseFields is
|
||||||
|
@ -52,6 +52,7 @@ public class ComponentClass {
|
|||||||
@Getter
|
@Getter
|
||||||
private String component, componentStr;
|
private String component, componentStr;
|
||||||
private String registryType;
|
private String registryType;
|
||||||
|
@Getter
|
||||||
private String componentIdentifier;
|
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 com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||||
|
import hirs.attestationca.persist.service.ReferenceManifestService;
|
||||||
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
|
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
|
||||||
|
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
|
||||||
import hirs.utils.SwidResource;
|
import hirs.utils.SwidResource;
|
||||||
import hirs.utils.xjc.BaseElement;
|
import hirs.utils.xjc.BaseElement;
|
||||||
import hirs.utils.xjc.Directory;
|
import hirs.utils.xjc.Directory;
|
||||||
@ -93,6 +95,105 @@ public class BaseReferenceManifest extends ReferenceManifest {
|
|||||||
private String linkHref = null;
|
private String linkHref = null;
|
||||||
private String linkRel = 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.
|
* 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
|
* 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
|
* 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 com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||||
import hirs.attestationca.persist.enums.AppraisalStatus;
|
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.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.EnumType;
|
import jakarta.persistence.EnumType;
|
||||||
import jakarta.persistence.Enumerated;
|
import jakarta.persistence.Enumerated;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
import java.io.IOException;
|
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.
|
* Sub class that will just focus on PCR Values and Events.
|
||||||
* Similar to {@link SupportReferenceManifest}
|
* Similar to {@link SupportReferenceManifest}
|
||||||
* however this is the live log from the client.
|
* however this is the live log from the client.
|
||||||
*/
|
*/
|
||||||
|
@Log4j2
|
||||||
|
@EqualsAndHashCode(callSuper=false)
|
||||||
@Entity
|
@Entity
|
||||||
public class EventLogMeasurements extends ReferenceManifest {
|
public class EventLogMeasurements extends ReferenceManifest {
|
||||||
|
|
||||||
@ -28,6 +41,66 @@ public class EventLogMeasurements extends ReferenceManifest {
|
|||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
private AppraisalStatus.Status overallValidationResult = AppraisalStatus.Status.FAIL;
|
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.
|
* Support constructor for the RIM object.
|
||||||
*
|
*
|
||||||
@ -61,4 +134,57 @@ public class EventLogMeasurements extends ReferenceManifest {
|
|||||||
super();
|
super();
|
||||||
this.pcrHash = 0;
|
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 com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
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.TCGEventLog;
|
||||||
import hirs.utils.tpm.eventlog.TpmPcrEvent;
|
import hirs.utils.tpm.eventlog.TpmPcrEvent;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
@ -34,6 +36,78 @@ public class SupportReferenceManifest extends ReferenceManifest {
|
|||||||
@Column
|
@Column
|
||||||
private boolean processed = false;
|
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
|
* Main constructor for the RIM object. This takes in a byte array of a
|
||||||
* valid swidtag file and parses the information.
|
* valid swidtag file and parses the information.
|
||||||
@ -69,6 +143,16 @@ public class SupportReferenceManifest extends ReferenceManifest {
|
|||||||
this.pcrHash = 0;
|
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
|
* Getter method for the expected PCR values contained within the support
|
||||||
@ -111,4 +195,13 @@ public class SupportReferenceManifest extends ReferenceManifest {
|
|||||||
|
|
||||||
return new ArrayList<>();
|
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;
|
package hirs.attestationca.persist.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to capture appraisal results and corresponding messages.
|
* Class to capture appraisal results and corresponding messages.
|
||||||
*/
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class AppraisalStatus {
|
public class AppraisalStatus {
|
||||||
/**
|
/**
|
||||||
* Enum used to represent appraisal status.
|
* Enum used to represent appraisal status.
|
||||||
@ -56,51 +61,4 @@ public class AppraisalStatus {
|
|||||||
this.additionalInfo = additionalInfo;
|
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.manager.CertificateRepository;
|
||||||
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
import hirs.attestationca.persist.entity.userdefined.Certificate;
|
||||||
|
import hirs.attestationca.persist.service.selector.CertificateSelector;
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class CertificateServiceImpl {
|
public class CertificateServiceImpl<T extends Certificate> extends DefaultDbService<Certificate> implements CertificateService<Certificate> {
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CertificateRepository repository;
|
private CertificateRepository repository;
|
||||||
|
|
||||||
private void saveCertificate(Certificate certificate) {
|
@Override
|
||||||
repository.save(certificate);
|
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;
|
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.manager.ReferenceManifestRepository;
|
||||||
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
|
||||||
|
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
@ -13,10 +18,14 @@ import javax.xml.validation.Schema;
|
|||||||
import javax.xml.validation.SchemaFactory;
|
import javax.xml.validation.SchemaFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@Service
|
@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.
|
* The variable that establishes a schema factory for xml processing.
|
||||||
@ -67,4 +76,69 @@ public class ReferenceManifestServiceImpl {
|
|||||||
}
|
}
|
||||||
return schema;
|
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();
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||||
@Autowired
|
@Autowired
|
||||||
static SettingsServiceImpl settingsService = new SettingsServiceImpl();
|
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;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
@ -17,15 +19,29 @@ import org.springframework.transaction.PlatformTransactionManager;
|
|||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
@PropertySource({ "classpath:hibernate.properties" })
|
@PropertySource({ "classpath:hibernate.properties", "classpath:portal.properties" })
|
||||||
@ComponentScan({ "hirs.attestationca.portal.page" })
|
@ComponentScan({ "hirs.attestationca.portal.page.controllers", "hirs.attestationca.persist.entity" })
|
||||||
@EnableJpaRepositories(basePackages = "hirs.attestationca.persist")
|
@EnableJpaRepositories(basePackages = "hirs.attestationca.persist.entity.manager")
|
||||||
public class PersistenceJPAConfig {
|
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
|
@Autowired
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
@ -53,6 +69,97 @@ public class PersistenceJPAConfig {
|
|||||||
return dataSource;
|
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
|
@Bean
|
||||||
public PlatformTransactionManager transactionManager() {
|
public PlatformTransactionManager transactionManager() {
|
||||||
final JpaTransactionManager transactionManager = new JpaTransactionManager();
|
final JpaTransactionManager transactionManager = new JpaTransactionManager();
|
||||||
@ -76,11 +183,11 @@ public class PersistenceJPAConfig {
|
|||||||
|
|
||||||
return hibernateProperties;
|
return hibernateProperties;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// @Bean(name="default-settings")
|
@Bean(name="default-settings")
|
||||||
// public SupplyChainSettings supplyChainSettings() {
|
public SupplyChainSettings supplyChainSettings() {
|
||||||
// SupplyChainSettings scSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
|
SupplyChainSettings scSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
|
||||||
//
|
|
||||||
// return scSettings;
|
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;
|
package hirs.attestationca.portal.datatables;
|
||||||
|
|
||||||
|
import hirs.attestationca.persist.FilteredRecordsList;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@ -30,11 +31,11 @@ public final class DataTableResponse<T> {
|
|||||||
* @param recordList the filtered record list
|
* @param recordList the filtered record list
|
||||||
* @param inputQuery the data table input (used for draw)
|
* @param inputQuery the data table input (used for draw)
|
||||||
*/
|
*/
|
||||||
// public DataTableResponse(final FilteredRecordsList<T> recordList,
|
public DataTableResponse(final FilteredRecordsList<T> recordList,
|
||||||
// final DataTableInput inputQuery) {
|
final DataTableInput inputQuery) {
|
||||||
// this(recordList, inputQuery.getDraw(),
|
this(recordList, inputQuery.getDraw(),
|
||||||
// recordList.getRecordsTotal(), recordList.getRecordsFiltered());
|
recordList.getRecordsTotal(), recordList.getRecordsFiltered());
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a data table response using the specified data with the data table specific
|
* 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;
|
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.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.persist.service.CertificateServiceImpl;
|
||||||
import hirs.attestationca.portal.page.Page;
|
import hirs.attestationca.portal.page.Page;
|
||||||
import hirs.attestationca.portal.page.PageController;
|
import hirs.attestationca.portal.page.PageController;
|
||||||
|
import hirs.attestationca.portal.page.PageMessages;
|
||||||
import hirs.attestationca.portal.page.params.NoPageParams;
|
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 lombok.extern.log4j.Log4j2;
|
||||||
|
import org.bouncycastle.util.encoders.DecoderException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
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.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.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
|
@Log4j2
|
||||||
@Controller
|
@Controller
|
||||||
@ -34,12 +65,12 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
|||||||
* Constructor providing the Page's display and routing specification.
|
* Constructor providing the Page's display and routing specification.
|
||||||
*
|
*
|
||||||
* @param certificateServiceImpl the certificate manager
|
* @param certificateServiceImpl the certificate manager
|
||||||
* @param crudManager the CRUD manager for certificates
|
// * @param crudManager the CRUD manager for certificates
|
||||||
* @param acaCertificate the ACA's X509 certificate
|
// * @param acaCertificate the ACA's X509 certificate
|
||||||
*/
|
*/
|
||||||
@Autowired
|
@Autowired
|
||||||
public CertificatePageController(
|
public CertificatePageController(
|
||||||
final CertificateServiceImpl certificateServiceImpl
|
final CertificateServiceImpl certificateServiceImpl//,
|
||||||
// final CrudManager<Certificate> crudManager,
|
// final CrudManager<Certificate> crudManager,
|
||||||
// final X509Certificate acaCertificate
|
// final X509Certificate acaCertificate
|
||||||
) {
|
) {
|
||||||
@ -48,12 +79,12 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
|||||||
// this.dataTableQuerier = crudManager;
|
// this.dataTableQuerier = crudManager;
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
//// certificateAuthorityCredential
|
// certificateAuthorityCredential
|
||||||
//// = new CertificateAuthorityCredential(acaCertificate.getEncoded());
|
// = new CertificateAuthorityCredential(acaCertificate.getEncoded());
|
||||||
// } catch (IOException e) {
|
// } catch (IOException ioEx) {
|
||||||
// log.error("Failed to read ACA certificate", e);
|
// log.error("Failed to read ACA certificate", ioEx);
|
||||||
// } catch (CertificateEncodingException e) {
|
// } catch (CertificateEncodingException ceEx) {
|
||||||
// log.error("Error getting encoded ACA certificate", e);
|
// 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) {
|
public ModelAndView initPage(final NoPageParams params, final Model model) {
|
||||||
return getBaseModelAndView();
|
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