Merge branch 'master' into event-digest-update

This commit is contained in:
Cyrus 2021-04-13 08:50:42 -04:00
commit 5a82e48b61
11 changed files with 238 additions and 119 deletions

View File

@ -461,7 +461,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
int algorithmLength = baseline[0].length(); int algorithmLength = baseline[0].length();
String[] storedPcrs = buildStoredPcrs(pcrContent, algorithmLength); String[] storedPcrs = buildStoredPcrs(pcrContent, algorithmLength);
if (storedPcrs[0].isEmpty()) { if (storedPcrs[0] == null || storedPcrs[0].isEmpty()) {
// validation fail // validation fail
fwStatus = new AppraisalStatus(FAIL, fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: " "Firmware validation failed: "

View File

@ -35,15 +35,17 @@ import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
/** /**
* Controller for the Validation Reports page. * Controller for the Validation Reports page.
@ -59,7 +61,7 @@ public class ValidationReportsPageController extends PageController<NoPageParams
private static String columnHeaders = "Verified Manufacturer," private static String columnHeaders = "Verified Manufacturer,"
+ "Model,SN,Verification Date,Device Status," + "Model,SN,Verification Date,Device Status,"
+ "Component name,Component manufacturer,Component model," + "Component name,Component manufacturer,Component model,"
+ "Component SN,Component status"; + "Component SN,Issuer,Component status";
private static final String DEFAULT_COMPANY = "AllDevices"; private static final String DEFAULT_COMPANY = "AllDevices";
private static final String UNDEFINED = "undefined"; private static final String UNDEFINED = "undefined";
private static final Logger LOGGER = getLogger(ValidationReportsPageController.class); private static final Logger LOGGER = getLogger(ValidationReportsPageController.class);
@ -138,6 +140,7 @@ public class ValidationReportsPageController extends PageController<NoPageParams
* @param response object * @param response object
* @throws IOException thrown by BufferedWriter object * @throws IOException thrown by BufferedWriter object
*/ */
@SuppressWarnings("checkstyle:magicnumber")
@RequestMapping(value = "download", method = RequestMethod.POST) @RequestMapping(value = "download", method = RequestMethod.POST)
public void download(final HttpServletRequest request, public void download(final HttpServletRequest request,
final HttpServletResponse response) throws IOException { final HttpServletResponse response) throws IOException {
@ -190,7 +193,8 @@ public class ValidationReportsPageController extends PageController<NoPageParams
} }
break; break;
case "createTimes": case "createTimes":
if (!parameterValue.equals(UNDEFINED)) { if (!parameterValue.equals(UNDEFINED)
&& !parameterValue.isEmpty()) {
String[] timestamps = parameterValue.split(","); String[] timestamps = parameterValue.split(",");
for (String timestamp : timestamps) { for (String timestamp : timestamps) {
createTimes.add(LocalDateTime.parse(timestamp, createTimes.add(LocalDateTime.parse(timestamp,
@ -199,7 +203,8 @@ public class ValidationReportsPageController extends PageController<NoPageParams
} }
break; break;
case "deviceNames": case "deviceNames":
if (!parameterValue.equals(UNDEFINED)) { if (!parameterValue.equals(UNDEFINED)
&& !parameterValue.isEmpty()) {
deviceNames = parameterValue.split(","); deviceNames = parameterValue.split(",");
} }
break; break;
@ -211,7 +216,7 @@ public class ValidationReportsPageController extends PageController<NoPageParams
response.setHeader("Content-Disposition", response.setHeader("Content-Disposition",
"attachment;filename=validation_report.csv"); "attachment;filename=validation_report.csv");
BufferedWriter bufferedWriter = new BufferedWriter( BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(response.getOutputStream(), "UTF-8")); new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
StringBuilder reportData = new StringBuilder(); StringBuilder reportData = new StringBuilder();
bufferedWriter.append("Company: " + company + "\n"); bufferedWriter.append("Company: " + company + "\n");
bufferedWriter.append("Contract number: " + contractNumber + "\n"); bufferedWriter.append("Contract number: " + contractNumber + "\n");
@ -237,7 +242,9 @@ public class ValidationReportsPageController extends PageController<NoPageParams
reportData.deleteCharAt(reportData.length() - 1); reportData.deleteCharAt(reportData.length() - 1);
reportData.append("\n,,,,,"); reportData.append("\n,,,,,");
} }
reportData.delete(reportData.lastIndexOf("\n"), reportData.length()); if (reportData.lastIndexOf(",") > 4) {
reportData.delete(reportData.lastIndexOf(",") - 4, reportData.length());
}
} }
} }
bufferedWriter.append(columnHeaders + "\n"); bufferedWriter.append(columnHeaders + "\n");
@ -259,13 +266,42 @@ public class ValidationReportsPageController extends PageController<NoPageParams
*/ */
private ArrayList<ArrayList<String>> parseComponents(final PlatformCredential pc) { private ArrayList<ArrayList<String>> parseComponents(final PlatformCredential pc) {
ArrayList<ArrayList<String>> parsedComponents = new ArrayList<ArrayList<String>>(); ArrayList<ArrayList<String>> parsedComponents = new ArrayList<ArrayList<String>>();
ArrayList<ArrayList<Object>> chainComponents = new ArrayList<>();
StringBuilder componentFailureString = new StringBuilder();
if (pc.getComponentIdentifiers() != null if (pc.getComponentIdentifiers() != null
&& pc.getComponentIdentifiers().size() > 0) { && pc.getComponentIdentifiers().size() > 0) {
LOGGER.info("Component failures: " + pc.getComponentFailures()); componentFailureString.append(pc.getComponentFailures());
ArrayList<String> componentFailures = // get all the certificates associated with the platform serial
new ArrayList<String>(Arrays.asList(pc.getComponentFailures().split(";"))); List<PlatformCredential> chainCertificates = PlatformCredential
.select(certificateManager)
.byBoardSerialNumber(pc.getPlatformSerial())
.getCertificates().stream().collect(Collectors.toList());
// combine all components in each certificate
for (ComponentIdentifier ci : pc.getComponentIdentifiers()) { for (ComponentIdentifier ci : pc.getComponentIdentifiers()) {
ArrayList<Object> issuerAndComponent = new ArrayList<Object>();
issuerAndComponent.add(pc.getIssuer());
issuerAndComponent.add(ci);
chainComponents.add(issuerAndComponent);
}
for (PlatformCredential cert : chainCertificates) {
componentFailureString.append(cert.getComponentFailures());
if (!cert.isBase()) {
for (ComponentIdentifier ci : cert.getComponentIdentifiers()) {
ArrayList<Object> issuerAndComponent = new ArrayList<Object>();
issuerAndComponent.add(cert.getIssuer());
issuerAndComponent.add(ci);
chainComponents.add(issuerAndComponent);
}
}
}
LOGGER.info("Component failures: " + componentFailureString.toString());
for (ArrayList<Object> issuerAndComponent : chainComponents) {
ArrayList<String> componentData = new ArrayList<String>(); ArrayList<String> componentData = new ArrayList<String>();
String issuer = (String) issuerAndComponent.get(0);
issuer = issuer.replaceAll(",", " ");
ComponentIdentifier ci = (ComponentIdentifier) issuerAndComponent.get(1);
if (ci instanceof ComponentIdentifierV2) { if (ci instanceof ComponentIdentifierV2) {
componentData.add(((ComponentIdentifierV2) ci).getComponentClass().toString()); componentData.add(((ComponentIdentifierV2) ci).getComponentClass().toString());
} else { } else {
@ -274,8 +310,9 @@ public class ValidationReportsPageController extends PageController<NoPageParams
componentData.add(ci.getComponentManufacturer().getString()); componentData.add(ci.getComponentManufacturer().getString());
componentData.add(ci.getComponentModel().getString()); componentData.add(ci.getComponentModel().getString());
componentData.add(ci.getComponentSerial().getString()); componentData.add(ci.getComponentSerial().getString());
//Failing components are identified by manufacturer + model componentData.add(issuer);
if (componentFailures.contains(componentData.get(1) + componentData.get(2))) { //Failing components are identified by hashcode
if (componentFailureString.toString().contains(String.valueOf(ci.hashCode()))) {
componentData.add("Fail"); componentData.add("Fail");
} else { } else {
componentData.add("Pass"); componentData.add("Pass");

View File

@ -53,10 +53,10 @@ public final class CertificateStringMapBuilder {
if (certificate != null) { if (certificate != null) {
data.put("issuer", certificate.getIssuer()); data.put("issuer", certificate.getIssuer());
//Serial number in hex value //Serial number in hex value
data.put("serialNumber", Long.toHexString(certificate.getSerialNumber().longValue())); data.put("serialNumber", Hex.toHexString(certificate.getSerialNumber().toByteArray()));
if (!certificate.getAuthoritySerialNumber().equals(BigInteger.ZERO)) { if (!certificate.getAuthoritySerialNumber().equals(BigInteger.ZERO)) {
data.put("authSerialNumber", Long.toHexString(certificate data.put("authSerialNumber", Hex.toHexString(certificate
.getAuthoritySerialNumber().longValue())); .getAuthoritySerialNumber().toByteArray()));
} }
if (certificate.getId() != null) { if (certificate.getId() != null) {
data.put("certificateId", certificate.getId().toString()); data.put("certificateId", certificate.getId().toString());
@ -103,20 +103,30 @@ public final class CertificateStringMapBuilder {
if (data.get("isSelfSigned").equals("false")) { if (data.get("isSelfSigned").equals("false")) {
//Get the missing certificate chain for not self sign //Get the missing certificate chain for not self sign
Certificate missingCert = containsAllChain(certificate, certificateManager); Certificate missingCert = containsAllChain(certificate, certificateManager);
String issuerResult;
if (missingCert != null) { if (missingCert != null) {
data.put("missingChainIssuer", missingCert.getIssuer()); data.put("missingChainIssuer", String.format("Missing %s from the chain.",
missingCert.getIssuer()));
} }
//Find all certificates that could be the issuer certificate based on subject name //Find all certificates that could be the issuer certificate based on subject name
for (Certificate issuerCert : CertificateAuthorityCredential for (Certificate issuerCert : CertificateAuthorityCredential
.select(certificateManager) .select(certificateManager)
.bySubject(certificate.getIssuer()) .bySubjectSorted(certificate.getIssuerSorted())
.getCertificates()) { .getCertificates()) {
try { try {
//Find the certificate that actually signed this cert //Find the certificate that actually signed this cert
if (certificate.isIssuer(issuerCert)) { issuerResult = certificate.isIssuer(issuerCert);
if (issuerResult.isEmpty()) {
data.put("issuerID", issuerCert.getId().toString()); data.put("issuerID", issuerCert.getId().toString());
break; break;
} else {
data.put("issuerID", issuerCert.getId().toString());
issuerResult = String.format("%s: %s", issuerResult,
issuerCert.getSubject());
data.put("missingChainIssuer", issuerResult);
break;
} }
} catch (IOException e) { } catch (IOException e) {
LOGGER.error(e); LOGGER.error(e);
@ -139,6 +149,7 @@ public final class CertificateStringMapBuilder {
final CertificateManager certificateManager) { final CertificateManager certificateManager) {
Set<CertificateAuthorityCredential> issuerCertificates = new HashSet<>(); Set<CertificateAuthorityCredential> issuerCertificates = new HashSet<>();
CertificateAuthorityCredential skiCA = null; CertificateAuthorityCredential skiCA = null;
String issuerResult;
//Check if there is a subject organization //Check if there is a subject organization
if (certificate.getAuthKeyId() != null if (certificate.getAuthKeyId() != null
&& !certificate.getAuthKeyId().isEmpty()) { && !certificate.getAuthKeyId().isEmpty()) {
@ -147,7 +158,7 @@ public final class CertificateStringMapBuilder {
.select(certificateManager) .select(certificateManager)
.bySubjectKeyIdentifier(bytes).getCertificate(); .bySubjectKeyIdentifier(bytes).getCertificate();
} else { } else {
LOGGER.info(String.format("Certificate (%s) for %s has no authority key identifier.", LOGGER.error(String.format("Certificate (%s) for %s has no authority key identifier.",
certificate.getClass().toString(), certificate.getSubject())); certificate.getClass().toString(), certificate.getSubject()));
} }
@ -171,7 +182,8 @@ public final class CertificateStringMapBuilder {
for (Certificate issuerCert : issuerCertificates) { for (Certificate issuerCert : issuerCertificates) {
try { try {
// Find the certificate that actually signed this cert // Find the certificate that actually signed this cert
if (certificate.isIssuer(issuerCert)) { issuerResult = certificate.isIssuer(issuerCert);
if (issuerResult.isEmpty()) {
//Check if it's root certificate //Check if it's root certificate
if (BouncyCastleUtils.x500NameCompare(issuerCert.getIssuer(), if (BouncyCastleUtils.x500NameCompare(issuerCert.getIssuer(),
issuerCert.getSubject())) { issuerCert.getSubject())) {

View File

@ -88,7 +88,7 @@
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<img src="${icons}/ic_error_red_24dp.png" <img src="${icons}/ic_error_red_24dp.png"
title="Missing ${initialData.missingChainIssuer} from the chain."> title="${initialData.missingChainIssuer}">
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
</span> </span>

View File

@ -8,31 +8,34 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 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.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
import org.bouncycastle.asn1.x509.AttCertIssuer;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.V2Form;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DLSequence; import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AccessDescription; import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AttCertIssuer;
import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess; import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.V2Form;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.x509.extension.X509ExtensionUtil; import org.bouncycastle.x509.extension.X509ExtensionUtil;
import javax.persistence.Column; import javax.persistence.Column;
@ -64,9 +67,6 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Objects; import java.util.Objects;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
/** /**
@ -753,8 +753,8 @@ public abstract class Certificate extends ArchivableEntity {
* @return whether or not the other certificate is the issuer for this certificate * @return whether or not the other certificate is the issuer for this certificate
* @throws IOException if there is an issue deserializing either certificate * @throws IOException if there is an issue deserializing either certificate
*/ */
public boolean isIssuer(final Certificate issuer) throws IOException { public String isIssuer(final Certificate issuer) throws IOException {
boolean isIssuer = false; String isIssuer = "Certificate signature failed to verify";
// only run if of the correct type, otherwise false // only run if of the correct type, otherwise false
if (issuer.getCertificateType() == CertificateType.X509_CERTIFICATE) { if (issuer.getCertificateType() == CertificateType.X509_CERTIFICATE) {
X509Certificate issuerX509 = issuer.getX509Certificate(); X509Certificate issuerX509 = issuer.getX509Certificate();
@ -764,7 +764,7 @@ public abstract class Certificate extends ArchivableEntity {
X509Certificate certX509 = getX509Certificate(); X509Certificate certX509 = getX509Certificate();
try { try {
certX509.verify(issuerX509.getPublicKey()); certX509.verify(issuerX509.getPublicKey());
isIssuer = true; isIssuer = "";
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException } catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException
| NoSuchProviderException | SignatureException e) { | NoSuchProviderException | SignatureException e) {
LOGGER.error(e); LOGGER.error(e);
@ -777,7 +777,9 @@ public abstract class Certificate extends ArchivableEntity {
Signature sig = Signature.getInstance(algorithm); Signature sig = Signature.getInstance(algorithm);
sig.initVerify(issuerX509.getPublicKey()); sig.initVerify(issuerX509.getPublicKey());
sig.update(attCert.getAcinfo().getEncoded()); sig.update(attCert.getAcinfo().getEncoded());
isIssuer = sig.verify(attCert.getSignatureValue().getBytes()); if (sig.verify(attCert.getSignatureValue().getBytes())) {
isIssuer = "";
}
} catch (NoSuchAlgorithmException } catch (NoSuchAlgorithmException
| InvalidKeyException | InvalidKeyException
| SignatureException e) { | SignatureException e) {

View File

@ -4,22 +4,11 @@ import com.google.common.base.Preconditions;
import hirs.data.persist.certificate.attributes.ComponentIdentifier; import hirs.data.persist.certificate.attributes.ComponentIdentifier;
import hirs.data.persist.certificate.attributes.PlatformConfiguration; import hirs.data.persist.certificate.attributes.PlatformConfiguration;
import hirs.data.persist.certificate.attributes.PlatformConfigurationV1; import hirs.data.persist.certificate.attributes.PlatformConfigurationV1;
import hirs.data.persist.certificate.attributes.V2.PlatformConfigurationV2;
import hirs.data.persist.certificate.attributes.TBBSecurityAssertion; import hirs.data.persist.certificate.attributes.TBBSecurityAssertion;
import hirs.data.persist.certificate.attributes.URIReference; import hirs.data.persist.certificate.attributes.URIReference;
import hirs.data.persist.certificate.attributes.V2.PlatformConfigurationV2;
import hirs.persist.CertificateManager; import hirs.persist.CertificateManager;
import hirs.persist.CertificateSelector; import hirs.persist.CertificateSelector;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Transient;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -37,15 +26,26 @@ import org.bouncycastle.asn1.x509.Attribute;
import org.bouncycastle.asn1.x509.AttributeCertificate; import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.bouncycastle.asn1.x509.AttributeCertificateInfo; import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
import org.bouncycastle.asn1.x509.CertificatePolicies; import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.PolicyQualifierInfo;
import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.PolicyQualifierInfo;
import org.bouncycastle.asn1.x509.UserNotice; import org.bouncycastle.asn1.x509.UserNotice;
import org.bouncycastle.operator.ContentVerifier; import org.bouncycastle.operator.ContentVerifier;
import org.bouncycastle.operator.ContentVerifierProvider; import org.bouncycastle.operator.ContentVerifierProvider;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Transient;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/** /**
* This class persists Platform credentials by extending the base Certificate * This class persists Platform credentials by extending the base Certificate
* class with fields unique to a Platform credentials, as defined in the Trusted * class with fields unique to a Platform credentials, as defined in the Trusted
@ -89,8 +89,21 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
* 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<String, String>() {{
put("#00000000", "Client"); put("#00000000", "Unclassified");
put("#00000001", "Server"); put("#00000001", "PC Client");
put("#00000002", "PDA");
put("#00000003", "CELLPHONE");
put("#00000004", "SERVER");
put("#00000005", "PERIPHERAL");
put("#00000006", "TSS");
put("#00000007", "STORAGE");
put("#00000008", "AUTHENTICATION");
put("#00000009", "EMBEDDED");
put("#00000010", "HARD COPY");
put("#00000011", "INFRASTRUCTURE");
put("#00000012", "VIRTUALIZATION");
put("#00000013", "TNC");
put("#00000014", "MULTI-TENANT");
}}; }};
// number of extra bytes potentially present in a cert header. // number of extra bytes potentially present in a cert header.

View File

@ -4,17 +4,21 @@ import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import hirs.data.persist.AppraisalStatus; import hirs.data.persist.AppraisalStatus;
import hirs.data.persist.info.ComponentInfo; import hirs.data.persist.ArchivableEntity;
import hirs.data.persist.DeviceInfoReport; import hirs.data.persist.DeviceInfoReport;
import hirs.data.persist.info.HardwareInfo; import hirs.data.persist.SupplyChainValidation;
import hirs.data.persist.certificate.EndorsementCredential; import hirs.data.persist.certificate.EndorsementCredential;
import hirs.data.persist.certificate.PlatformCredential; import hirs.data.persist.certificate.PlatformCredential;
import hirs.data.persist.certificate.attributes.ComponentIdentifier; import hirs.data.persist.certificate.attributes.ComponentIdentifier;
import hirs.data.persist.certificate.attributes.V2.ComponentIdentifierV2;
import hirs.data.persist.info.ComponentInfo;
import hirs.data.persist.info.HardwareInfo;
import org.apache.commons.codec.Charsets; import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.Strings;
import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.CertException; import org.bouncycastle.cert.CertException;
@ -41,11 +45,14 @@ import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -55,13 +62,6 @@ import java.util.stream.Collectors;
import static hirs.data.persist.AppraisalStatus.Status.ERROR; import static hirs.data.persist.AppraisalStatus.Status.ERROR;
import static hirs.data.persist.AppraisalStatus.Status.FAIL; import static hirs.data.persist.AppraisalStatus.Status.FAIL;
import static hirs.data.persist.AppraisalStatus.Status.PASS; import static hirs.data.persist.AppraisalStatus.Status.PASS;
import hirs.data.persist.ArchivableEntity;
import hirs.data.persist.SupplyChainValidation;
import hirs.data.persist.certificate.attributes.V2.ComponentIdentifierV2;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import org.apache.logging.log4j.util.Strings;
/** /**
@ -196,6 +196,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
final boolean acceptExpired) { final boolean acceptExpired) {
final String baseErrorMessage = "Can't validate platform credential without "; final String baseErrorMessage = "Can't validate platform credential without ";
String message; String message;
String certVerifyMsg;
if (pc == null) { if (pc == null) {
message = baseErrorMessage + "a platform credential\n"; message = baseErrorMessage + "a platform credential\n";
LOGGER.error(message); LOGGER.error(message);
@ -233,19 +234,21 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// verify cert against truststore // verify cert against truststore
try { try {
if (verifyCertificate(attributeCert, trustStore)) { certVerifyMsg = verifyCertificate(attributeCert, trustStore);
if (certVerifyMsg.isEmpty()) {
message = PLATFORM_VALID; message = PLATFORM_VALID;
LOGGER.info(message); LOGGER.info(message);
return new AppraisalStatus(PASS, message); return new AppraisalStatus(PASS, message);
} else { } else {
message = "Platform credential failed verification"; message = String.format("Platform credential failed verification%n%s",
certVerifyMsg);
LOGGER.error(message); LOGGER.error(message);
return new AppraisalStatus(FAIL, message); return new AppraisalStatus(FAIL, message);
} }
} catch (SupplyChainValidatorException e) { } catch (SupplyChainValidatorException scvEx) {
message = "An error occurred indicating the credential is not valid"; message = "An error occurred indicating the credential is not valid";
LOGGER.warn(message, e); LOGGER.warn(message, scvEx);
return new AppraisalStatus(FAIL, message + " " + e.getMessage()); return new AppraisalStatus(FAIL, message + " " + scvEx.getMessage());
} }
} }
@ -1244,14 +1247,14 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* @throws SupplyChainValidatorException * @throws SupplyChainValidatorException
* if the verification is not successful * if the verification is not successful
*/ */
public static boolean verifyCertificate(final X509AttributeCertificateHolder cert, public static String verifyCertificate(final X509AttributeCertificateHolder cert,
final KeyStore trustStore) throws SupplyChainValidatorException { final KeyStore trustStore) throws SupplyChainValidatorException {
if (cert == null || trustStore == null) { if (cert == null || trustStore == null) {
throw new SupplyChainValidatorException("Certificate or trust store is null"); throw new SupplyChainValidatorException("Certificate or trust store is null");
} }
try { try {
Set<X509Certificate> trustedCerts = new HashSet<X509Certificate>(); Set<X509Certificate> trustedCerts = new HashSet<>();
Enumeration<String> alias = trustStore.aliases(); Enumeration<String> alias = trustStore.aliases();
@ -1259,15 +1262,14 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement())); trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
} }
boolean certChainValidated = validateCertChain(cert, trustedCerts); String certChainValidated = validateCertChain(cert, trustedCerts);
if (!certChainValidated) { if (!certChainValidated.isEmpty()) {
LOGGER.error("Cert chain could not be validated"); LOGGER.error("Cert chain could not be validated");
} }
return certChainValidated; return certChainValidated;
} catch (KeyStoreException e) { } catch (KeyStoreException e) {
throw new SupplyChainValidatorException("Error with the trust store", e); throw new SupplyChainValidatorException("Error with the trust store", e);
} }
} }
/** /**
@ -1291,7 +1293,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
throw new SupplyChainValidatorException("Certificate or trust store is null"); throw new SupplyChainValidatorException("Certificate or trust store is null");
} }
try { try {
Set<X509Certificate> trustedCerts = new HashSet<X509Certificate>(); Set<X509Certificate> trustedCerts = new HashSet<>();
Enumeration<String> alias = trustStore.aliases(); Enumeration<String> alias = trustStore.aliases();
@ -1299,7 +1301,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement())); trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
} }
return validateCertChain(cert, trustedCerts); return validateCertChain(cert, trustedCerts).isEmpty();
} catch (KeyStoreException e) { } catch (KeyStoreException e) {
LOGGER.error("Error accessing keystore", e); LOGGER.error("Error accessing keystore", e);
throw new SupplyChainValidatorException("Error with the trust store", e); throw new SupplyChainValidatorException("Error with the trust store", e);
@ -1321,31 +1323,40 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* @return boolean indicating if the validation was successful * @return boolean indicating if the validation was successful
* @throws SupplyChainValidatorException tried to validate using null certificates * @throws SupplyChainValidatorException tried to validate using null certificates
*/ */
public static boolean validateCertChain(final X509AttributeCertificateHolder cert, public static String validateCertChain(final X509AttributeCertificateHolder cert,
final Set<X509Certificate> additionalCerts) throws SupplyChainValidatorException { final Set<X509Certificate> additionalCerts) throws SupplyChainValidatorException {
if (cert == null || additionalCerts == null) { if (cert == null || additionalCerts == null) {
throw new SupplyChainValidatorException( throw new SupplyChainValidatorException(
"Certificate or validation certificates are null"); "Certificate or validation certificates are null");
} }
boolean foundRootOfCertChain = false; String foundRootOfCertChain = "";
Iterator<X509Certificate> certIterator = additionalCerts.iterator(); Iterator<X509Certificate> certIterator = additionalCerts.iterator();
X509Certificate trustedCert; X509Certificate trustedCert;
boolean issuerMatchesSubject = false;
boolean signatureMatchesPublicKey = false;
while (!foundRootOfCertChain && certIterator.hasNext()) { while (foundRootOfCertChain.isEmpty() && certIterator.hasNext()) {
trustedCert = certIterator.next(); trustedCert = certIterator.next();
if (issuerMatchesSubjectDN(cert, trustedCert) issuerMatchesSubject = issuerMatchesSubjectDN(cert, trustedCert);
&& signatureMatchesPublicKey(cert, trustedCert)) { signatureMatchesPublicKey = signatureMatchesPublicKey(cert, trustedCert);
if (issuerMatchesSubject && signatureMatchesPublicKey) {
if (isSelfSigned(trustedCert)) { if (isSelfSigned(trustedCert)) {
LOGGER.info("CA Root found."); LOGGER.info("CA Root found.");
foundRootOfCertChain = true;
} else { } else {
foundRootOfCertChain = validateCertChain(trustedCert, additionalCerts); foundRootOfCertChain = validateCertChain(trustedCert, additionalCerts);
if (!foundRootOfCertChain) { if (!foundRootOfCertChain.isEmpty()) {
LOGGER.error("Root of certificate chain not found. Check for CA Cert: " LOGGER.error("Root of certificate chain not found. Check for CA Cert: "
+ cert.getIssuer().getNames()[0]); + cert.getIssuer().getNames()[0]);
} }
} }
} else {
if (!issuerMatchesSubject) {
foundRootOfCertChain = "Issuer DN does not match Subject DN";
}
if (!signatureMatchesPublicKey) {
foundRootOfCertChain = "Certificate signature failed to verify";
}
} }
} }
@ -1366,31 +1377,40 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* @return boolean indicating if the validation was successful * @return boolean indicating if the validation was successful
* @throws SupplyChainValidatorException tried to validate using null certificates * @throws SupplyChainValidatorException tried to validate using null certificates
*/ */
public static boolean validateCertChain(final X509Certificate cert, public static String validateCertChain(final X509Certificate cert,
final Set<X509Certificate> additionalCerts) throws SupplyChainValidatorException { final Set<X509Certificate> additionalCerts) throws SupplyChainValidatorException {
if (cert == null || additionalCerts == null) { if (cert == null || additionalCerts == null) {
throw new SupplyChainValidatorException( throw new SupplyChainValidatorException(
"Certificate or validation certificates are null"); "Certificate or validation certificates are null");
} }
boolean foundRootOfCertChain = false; String foundRootOfCertChain = "";
Iterator<X509Certificate> certIterator = additionalCerts.iterator(); Iterator<X509Certificate> certIterator = additionalCerts.iterator();
X509Certificate trustedCert; X509Certificate trustedCert;
boolean issuerMatchesSubject = false;
boolean signatureMatchesPublicKey = false;
while (!foundRootOfCertChain && certIterator.hasNext()) { while (foundRootOfCertChain.isEmpty() && certIterator.hasNext()) {
trustedCert = certIterator.next(); trustedCert = certIterator.next();
if (issuerMatchesSubjectDN(cert, trustedCert) issuerMatchesSubject = issuerMatchesSubjectDN(cert, trustedCert);
&& signatureMatchesPublicKey(cert, trustedCert)) { signatureMatchesPublicKey = signatureMatchesPublicKey(cert, trustedCert);
if (issuerMatchesSubject && signatureMatchesPublicKey) {
if (isSelfSigned(trustedCert)) { if (isSelfSigned(trustedCert)) {
LOGGER.info("CA Root found."); LOGGER.info("CA Root found.");
foundRootOfCertChain = true;
} else if (!cert.equals(trustedCert)) { } else if (!cert.equals(trustedCert)) {
foundRootOfCertChain = validateCertChain(trustedCert, additionalCerts); foundRootOfCertChain = validateCertChain(trustedCert, additionalCerts);
if (!foundRootOfCertChain) { if (!foundRootOfCertChain.isEmpty()) {
LOGGER.error("Root of certificate chain not found. Check for CA Cert: " LOGGER.error("Root of certificate chain not found. Check for CA Cert: "
+ cert.getIssuerDN().getName()); + cert.getIssuerDN().getName());
} }
} }
} else {
if (!issuerMatchesSubject) {
foundRootOfCertChain = "Issuer DN does not match Subject DN";
}
if (!signatureMatchesPublicKey) {
foundRootOfCertChain = "Certificate signature failed to verify";
}
} }
} }
@ -1611,8 +1631,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
*/ */
public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert, public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert,
final X509Certificate signingCert) throws SupplyChainValidatorException { final X509Certificate signingCert) throws SupplyChainValidatorException {
if (cert == null || signingCert == null) { if (signingCert == null) {
throw new SupplyChainValidatorException("Certificate or signing certificate is null"); throw new SupplyChainValidatorException("Signing certificate is null");
} }
return signatureMatchesPublicKey(cert, signingCert.getPublicKey()); return signatureMatchesPublicKey(cert, signingCert.getPublicKey());
} }

View File

@ -441,8 +441,8 @@ public class CertificateTest {
Certificate issuerCert = getTestCertificate(FAKE_ROOT_CA_FILE); Certificate issuerCert = getTestCertificate(FAKE_ROOT_CA_FILE);
Certificate cert = getTestCertificate(INT_CA_CERT02); Certificate cert = getTestCertificate(INT_CA_CERT02);
Assert.assertFalse(issuerCert.isIssuer(cert)); Assert.assertFalse(!issuerCert.isIssuer(cert).isEmpty());
Assert.assertTrue(cert.isIssuer(issuerCert)); Assert.assertTrue(cert.isIssuer(issuerCert).isEmpty());
} }
/** /**

View File

@ -7,6 +7,7 @@ import hirs.data.persist.certificate.attributes.TBBSecurityAssertion;
import hirs.data.persist.certificate.attributes.URIReference; import hirs.data.persist.certificate.attributes.URIReference;
import hirs.data.persist.certificate.attributes.V2.PlatformConfigurationV2; import hirs.data.persist.certificate.attributes.V2.PlatformConfigurationV2;
import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.util.encoders.Base64;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -19,8 +20,6 @@ import java.util.Calendar;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.bouncycastle.util.encoders.Base64;
import static org.testng.Assert.fail; import static org.testng.Assert.fail;
/** /**
@ -405,7 +404,7 @@ public class PlatformCredentialTest {
Base64.decode(EXPECTED_CERT_SIGNATURE_FOR_CERT2_1)); Base64.decode(EXPECTED_CERT_SIGNATURE_FOR_CERT2_1));
//Check if issuer certificate issued the platform credential //Check if issuer certificate issued the platform credential
Assert.assertTrue(platformCert.isIssuer(issuer)); Assert.assertTrue(platformCert.isIssuer(issuer).isEmpty());
} }
/** /**

View File

@ -895,16 +895,17 @@ public class SupplyChainCredentialValidatorTest {
trustedCerts.add(caCert); trustedCerts.add(caCert);
trustedCerts.add(intermediateCert); trustedCerts.add(intermediateCert);
boolean assertion = SupplyChainCredentialValidator.validateCertChain(attrCert,
trustedCerts).isEmpty();
Assert.assertTrue(SupplyChainCredentialValidator.validateCertChain(attrCert, Assert.assertTrue(assertion);
trustedCerts));
try { try {
keyStore.setCertificateEntry("CA cert", caCert); keyStore.setCertificateEntry("CA cert", caCert);
keyStore.setCertificateEntry("Intermediate Cert", intermediateCert); keyStore.setCertificateEntry("Intermediate Cert", intermediateCert);
assertion = SupplyChainCredentialValidator.verifyCertificate(attrCert,
Assert.assertTrue(SupplyChainCredentialValidator.verifyCertificate(attrCert, keyStore).isEmpty();
keyStore)); Assert.assertTrue(assertion);
} catch (Exception e) { } catch (Exception e) {
Assert.fail("Unexpected error occurred while verifying certificate", e); Assert.fail("Unexpected error occurred while verifying certificate", e);
} }
@ -938,14 +939,16 @@ public class SupplyChainCredentialValidatorTest {
trustedCerts.add(caCert); trustedCerts.add(caCert);
Assert.assertFalse(SupplyChainCredentialValidator.validateCertChain(attrCert, boolean assertion = SupplyChainCredentialValidator.validateCertChain(attrCert,
trustedCerts)); trustedCerts).isEmpty();
Assert.assertFalse(assertion);
try { try {
keyStore.setCertificateEntry("CA cert", caCert); keyStore.setCertificateEntry("CA cert", caCert);
Assert.assertFalse(SupplyChainCredentialValidator.verifyCertificate(attrCert, assertion = SupplyChainCredentialValidator.verifyCertificate(attrCert,
keyStore)); keyStore).isEmpty();
Assert.assertFalse(assertion);
} catch (Exception e) { } catch (Exception e) {
Assert.fail("Unexpected error occurred while verifying certificate", e); Assert.fail("Unexpected error occurred while verifying certificate", e);
} }
@ -971,12 +974,16 @@ public class SupplyChainCredentialValidatorTest {
trustedCerts.add(caCert); trustedCerts.add(caCert);
Assert.assertTrue(SupplyChainCredentialValidator.validateCertChain(attrCert, trustedCerts)); boolean assertion = SupplyChainCredentialValidator.validateCertChain(
attrCert, trustedCerts).isEmpty();
Assert.assertTrue(assertion);
try { try {
keyStore.setCertificateEntry("CA cert", caCert); keyStore.setCertificateEntry("CA cert", caCert);
Assert.assertTrue(SupplyChainCredentialValidator.verifyCertificate(attrCert, keyStore)); assertion = SupplyChainCredentialValidator.verifyCertificate(
attrCert, keyStore).isEmpty();
Assert.assertTrue(assertion);
} catch (Exception e) { } catch (Exception e) {
Assert.fail("Unexpected error occurred while verifying certificate", e); Assert.fail("Unexpected error occurred while verifying certificate", e);
} }
@ -1008,8 +1015,9 @@ public class SupplyChainCredentialValidatorTest {
trustedCerts.add(caCert); trustedCerts.add(caCert);
trustedCerts.add(intermediateCert); trustedCerts.add(intermediateCert);
Assert.assertTrue(SupplyChainCredentialValidator.validateCertChain(targetCert, boolean assertion = SupplyChainCredentialValidator.validateCertChain(targetCert,
trustedCerts)); trustedCerts).isEmpty();
Assert.assertTrue(assertion);
try { try {
keyStore.setCertificateEntry("CA cert", caCert); keyStore.setCertificateEntry("CA cert", caCert);
@ -1046,8 +1054,9 @@ public class SupplyChainCredentialValidatorTest {
trustedCerts.add(caCert); trustedCerts.add(caCert);
Assert.assertFalse(SupplyChainCredentialValidator.validateCertChain(targetCert, boolean assertion = SupplyChainCredentialValidator.validateCertChain(targetCert,
trustedCerts)); trustedCerts).isEmpty();
Assert.assertFalse(assertion);
try { try {
keyStore.setCertificateEntry("CA cert", caCert); keyStore.setCertificateEntry("CA cert", caCert);
@ -1076,8 +1085,9 @@ public class SupplyChainCredentialValidatorTest {
trustedCerts.add(caCert); trustedCerts.add(caCert);
Assert.assertTrue(SupplyChainCredentialValidator.validateCertChain(targetCert, boolean assertion = SupplyChainCredentialValidator.validateCertChain(targetCert,
trustedCerts)); trustedCerts).isEmpty();
Assert.assertTrue(assertion);
try { try {
keyStore.setCertificateEntry("CA cert", caCert); keyStore.setCertificateEntry("CA cert", caCert);

View File

@ -0,0 +1,26 @@
#!/bin/bash
#User input parameters:
#$1 filter start date 'yyyy-mm-dd'
#$2 filter end date 'yyyy-mm-dd'
#$3 ACA address, default is localhost if not given
if [ -z "$3" ]
then
endpoint="https://localhost:8443/HIRS_AttestationCAPortal/portal/validation-reports"
else
endpoint="https://$3:8443/HIRS_AttestationCAPortal/portal/validation-reports"
fi
echo "$endpoint"
content=$(curl --insecure $endpoint/list)
rawTimes=$(jq -r '.data | map(.createTime | tostring) | join(",")' <<< "$content")
createTimes=""
for i in ${rawTimes//,/ }
do
createTimes+="$(date -u +"%Y-%m-%d %H:%M:%S" -d @"$(($i/1000))"),"
done
deviceNames=$(jq -r '.data | map(.device.name) | join(",")' <<< "$content")
echo "Create times: $createTimes"
echo "Device names: $deviceNames"
curl --data "dateStart=$1&dateEnd=$2&createTimes=$createTimes&deviceNames=$deviceNames" --insecure $endpoint/download