This latest push should have the code that'll highlight the components based on a string rather than the serial number. This also adds additional checks for the validity begin date of the delta not matching or being before the base. It also checks that they don't have the same certificate serial number.

This commit is contained in:
Cyrus 2020-12-30 08:41:47 -05:00
parent f38fa87013
commit 7028810707
5 changed files with 83 additions and 195 deletions

View File

@ -392,7 +392,6 @@ public abstract class AbstractAttestationCertificateAuthority
*/ */
@Override @Override
public byte[] processIdentityClaimTpm2(final byte[] identityClaim) { public byte[] processIdentityClaimTpm2(final byte[] identityClaim) {
LOG.debug("Got identity claim"); LOG.debug("Got identity claim");
if (ArrayUtils.isEmpty(identityClaim)) { if (ArrayUtils.isEmpty(identityClaim)) {
@ -414,7 +413,6 @@ public abstract class AbstractAttestationCertificateAuthority
LOG.error(ex); LOG.error(ex);
} }
if (validationResult == AppraisalStatus.Status.PASS) { if (validationResult == AppraisalStatus.Status.PASS) {
RSAPublicKey akPub = parsePublicKey(claim.getAkPublicArea().toByteArray()); RSAPublicKey akPub = parsePublicKey(claim.getAkPublicArea().toByteArray());
byte[] nonce = generateRandomBytes(NONCE_LENGTH); byte[] nonce = generateRandomBytes(NONCE_LENGTH);
ByteString blobStr = tpm20MakeCredential(ekPub, akPub, nonce); ByteString blobStr = tpm20MakeCredential(ekPub, akPub, nonce);
@ -454,11 +452,6 @@ public abstract class AbstractAttestationCertificateAuthority
Set<PlatformCredential> platformCredentials = parsePcsFromIdentityClaim(claim, Set<PlatformCredential> platformCredentials = parsePcsFromIdentityClaim(claim,
endorsementCredential); endorsementCredential);
Map<BigInteger, PlatformCredential> correctedMap = new HashMap<>(); Map<BigInteger, PlatformCredential> correctedMap = new HashMap<>();
for (PlatformCredential pc : platformCredentials) {
correctedMap.put(pc.getSerialNumber(), pc);
}
platformCredentials.clear();
platformCredentials.addAll(correctedMap.values());
// Parse and save device info // Parse and save device info
Device device = processDeviceInfo(claim); Device device = processDeviceInfo(claim);

View File

@ -84,7 +84,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
private static final Logger LOGGER private static final Logger LOGGER
= LogManager.getLogger(SupplyChainValidationServiceImpl.class); = LogManager.getLogger(SupplyChainValidationServiceImpl.class);
private static final int VALUE_INDEX = 1;
/** /**
* Constructor. * Constructor.
@ -132,9 +131,10 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
supplyChainAppraiser); supplyChainAppraiser);
boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled(); boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled();
PlatformCredential baseCredential = null; PlatformCredential baseCredential = null;
SupplyChainValidation platformScv = null;
String pcErrorMessage = "";
List<SupplyChainValidation> validations = new LinkedList<>(); List<SupplyChainValidation> validations = new LinkedList<>();
Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>(); Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>();
SupplyChainValidation platformScv = null;
SupplyChainValidation.ValidationType platformType = SupplyChainValidation SupplyChainValidation.ValidationType platformType = SupplyChainValidation
.ValidationType.PLATFORM_CREDENTIAL; .ValidationType.PLATFORM_CREDENTIAL;
SupplyChainValidation.ValidationType platformAttrType = SupplyChainValidation SupplyChainValidation.ValidationType platformAttrType = SupplyChainValidation
@ -158,41 +158,26 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
// Ensure there are platform credentials to validate // Ensure there are platform credentials to validate
if (pcs == null || pcs.isEmpty()) { if (pcs == null || pcs.isEmpty()) {
LOGGER.error("There were no Platform Credentials to validate."); LOGGER.error("There were no Platform Credentials to validate.");
validations.add(buildValidationRecord( pcErrorMessage = "Platform credential(s) missing\n";
platformType,
AppraisalStatus.Status.FAIL,
"Platform credential(s) missing", null, Level.ERROR));
} else { } else {
Iterator<PlatformCredential> it = pcs.iterator(); for (PlatformCredential pc : pcs) {
while (it.hasNext()) {
PlatformCredential pc = it.next();
KeyStore trustedCa = getCaChain(pc); KeyStore trustedCa = getCaChain(pc);
platformScv = validatePlatformCredential( platformScv = validatePlatformCredential(
pc, trustedCa, acceptExpiredCerts); pc, trustedCa, acceptExpiredCerts);
// check if this cert has been verified for multiple base if (platformScv.getResult() == FAIL) {
// associated with the serial number pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
if (pc != null) { platformScv.getMessage());
platformScv = validatePcPolicy(pc, platformScv,
deltaMapping, acceptExpiredCerts);
if (validationTypeMap.containsKey(
platformType)) {
SupplyChainValidation tmpScv = validationTypeMap.get(platformType);
if (tmpScv.getResult() == PASS && platformScv.getResult() == FAIL) {
validationTypeMap.put(platformType, platformScv);
} }
} else { // set the base credential
validationTypeMap.put(platformType, platformScv);
}
if (pc.isBase()) { if (pc.isBase()) {
baseCredential = pc; baseCredential = pc;
LOGGER.error("Found the base Certificate"); } else {
deltaMapping.put(pc, null);
} }
pc.setDevice(device); pc.setDevice(device);
this.certificateManager.update(pc); this.certificateManager.update(pc);
}
} }
// check that the delta certificates validity date is after // check that the delta certificates validity date is after
@ -202,130 +187,70 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
int result = pc.getBeginValidity() int result = pc.getBeginValidity()
.compareTo(baseCredential.getBeginValidity()); .compareTo(baseCredential.getBeginValidity());
if (!pc.isBase() && (result <= 0)) { if (!pc.isBase() && (result <= 0)) {
LOGGER.error("You are not crazy"); pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
validationTypeMap.put(platformType,
buildValidationRecord(
platformType,
AppraisalStatus.Status.FAIL,
"Delta Certificate's validity " "Delta Certificate's validity "
+ "date is not after Base", + "date is not after Base");
null, Level.ERROR));
break; break;
} }
} }
} else { } else {
// we don't have a base cert, fail // we don't have a base cert, fail
validationTypeMap.put(platformType, pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
buildValidationRecord( "Base Platform credential missing");
platformType, }
AppraisalStatus.Status.FAIL,
"Base Platform credential missing",
null,
Level.ERROR));
} }
validations.add(validationTypeMap.get( if (pcErrorMessage.isEmpty()) {
platformType)); validations.add(platformScv);
} else {
validations.add(new SupplyChainValidation(platformType,
AppraisalStatus.Status.FAIL, new ArrayList<>(pcs), pcErrorMessage));
} }
} }
// Validate Platform Credential attributes // Validate Platform Credential attributes
if (policy.isPcAttributeValidationEnabled()) { if (policy.isPcAttributeValidationEnabled()
&& pcErrorMessage.isEmpty()) {
// Ensure there are platform credentials to validate // Ensure there are platform credentials to validate
if (pcs == null || pcs.isEmpty()) {
LOGGER.error("There were no Platform Credentials to validate attributes.");
validations.add(buildValidationRecord(
platformAttrType,
AppraisalStatus.Status.FAIL,
"Platform credential(s) missing."
+ " Cannot validate attributes",
null, Level.ERROR));
} else {
platformScv = validationTypeMap.get(
platformType);
SupplyChainValidation attributeScv = null; SupplyChainValidation attributeScv = null;
List<ArchivableEntity> aes = new ArrayList<>(); List<ArchivableEntity> aes = new ArrayList<>();
if (platformScv != null) { if (platformScv != null) {
aes.addAll(platformScv.getCertificatesUsed()); aes.addAll(platformScv.getCertificatesUsed());
} }
// ok, still want to validate the base credential attributes
attributeScv = validatePlatformCredentialAttributes(
baseCredential, device.getDeviceInfo(), ec);
if (attributeScv.getResult() != FAIL) {
Iterator<PlatformCredential> it = pcs.iterator(); Iterator<PlatformCredential> it = pcs.iterator();
String attrErrorMessage = "";
while (it.hasNext()) { while (it.hasNext()) {
PlatformCredential pc = it.next(); PlatformCredential pc = it.next();
if (pc != null) { if (pc != null) {
if (pc.isDeltaChain()) { if (!pc.isBase() && attributeScv.getResult() != FAIL) {
// this check validates the delta changes and re-compares
// the modified list to the original.
attributeScv = validateDeltaPlatformCredentialAttributes( attributeScv = validateDeltaPlatformCredentialAttributes(
pc, device.getDeviceInfo(), pc, device.getDeviceInfo(),
baseCredential, deltaMapping); baseCredential, deltaMapping);
} else { if (attributeScv.getResult() == FAIL) {
attributeScv = validatePlatformCredentialAttributes( attrErrorMessage = String.format("%s%s%n", attrErrorMessage,
pc, device.getDeviceInfo(), ec); attributeScv.getMessage());
}
// update the attribute SCV
if (validationTypeMap.containsKey(platformAttrType)) {
SupplyChainValidation tmpScv = validationTypeMap.get(
platformAttrType);
if (tmpScv.getResult() == PASS && attributeScv.getResult() == FAIL) {
validationTypeMap.put(platformAttrType, attributeScv);
} else if (tmpScv.getResult() == FAIL
&& attributeScv.getResult() == FAIL) {
validationTypeMap.put(platformAttrType, new SupplyChainValidation(
attributeScv.getValidationType(),
attributeScv.getResult(), aes,
String.format("%s%n%s", tmpScv.getMessage(),
attributeScv.getMessage())));
}
} else {
validationTypeMap.put(platformAttrType, attributeScv);
}
// if (platformScv != null) {
// // have to make sure the attribute validation isn't ignored and
// // doesn't override general validation status
// if (platformScv.getResult() == PASS
// && attributeScv.getResult() != PASS) {
// // if the platform trust store validated but the attribute didn't
// // replace
// validationTypeMap.put(
// SupplyChainValidation.ValidationType
// .PLATFORM_CREDENTIAL_ATTRIBUTES,
// attributeScv);
// } else if ((platformScv.getResult() == PASS
// && attributeScv.getResult() == PASS)
// || (platformScv.getResult() != PASS
// && attributeScv.getResult() != PASS)) {
// // if both trust store and attributes validated or failed
// // combine messages
// validations.add(new SupplyChainValidation(
// platformScv.getValidationType(),
// platformScv.getResult(), aes,
// String.format("%s%n%s", platformScv.getMessage(),
// attributeScv.getMessage())));
// }
// }
pc.setDevice(device);
this.certificateManager.update(pc);
} }
} }
}
}
if (!attrErrorMessage.isEmpty()) {
//combine platform and platform attributes //combine platform and platform attributes
validations.remove(platformScv); validations.remove(platformScv);
attributeScv = validationTypeMap.get(
platformAttrType);
if (platformScv.getResult() == PASS && attributeScv.getResult() == FAIL) {
validations.add(new SupplyChainValidation( validations.add(new SupplyChainValidation(
platformScv.getValidationType(), platformScv.getValidationType(),
attributeScv.getResult(), aes, attributeScv.getMessage())); attributeScv.getResult(), aes, attributeScv.getMessage()));
} else if (platformScv.getResult() == FAIL && attributeScv.getResult() == FAIL) {
validations.add(new SupplyChainValidation(
platformScv.getValidationType(),
platformScv.getResult(), aes,
String.format("%s%n%s", platformScv.getMessage(),
attributeScv.getMessage())));
} }
} else {
validations.remove(platformScv);
// base platform has errors
validations.add(new SupplyChainValidation(platformScv.getValidationType(),
attributeScv.getResult(), aes, attributeScv.getMessage()));
} }
} }

View File

@ -275,7 +275,6 @@ public class ReferenceManifestDetailsPageController
for (CertificateAuthorityCredential cert : certificates) { for (CertificateAuthorityCredential cert : certificates) {
if (Arrays.equals(cert.getEncodedPublicKey(), if (Arrays.equals(cert.getEncodedPublicKey(),
RIM_VALIDATOR.getPublicKey().getEncoded())) { RIM_VALIDATOR.getPublicKey().getEncoded())) {
LOGGER.info("Found matching cert!");
data.put("issuerID", cert.getId().toString()); data.put("issuerID", cert.getId().toString());
} }
} }
@ -407,10 +406,6 @@ public class ReferenceManifestDetailsPageController
data.put("supportEvents", supportEvents); data.put("supportEvents", supportEvents);
data.put("livelogEvents", livelogEvents); data.put("livelogEvents", livelogEvents);
for (Map.Entry<String, Object> entry : data.entrySet()) {
LOGGER.error(String.format("%s -> %s", entry.getKey(),
String.valueOf(entry.getValue())));
}
return data; return data;
} }
} }

View File

@ -380,25 +380,16 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
/** /**
* Get the type of platform certificate. * Get the type of platform certificate.
* *
* @return the TCG platform type { base | delta } * @return flag for base certificate
*/ */
public boolean isBase() { public boolean isBase() {
return platformBase; return platformBase;
} }
/**
* Flag that indicates this PC has or can have a chain of delta
* certificates.
* @return status of the chain
*/
public boolean isDeltaChain() {
return isDeltaChain;
}
/** /**
* Getter for the string representation of the platform type. * Getter for the string representation of the platform type.
* *
* @return Delta or Base * @return the TCG platform type { base | delta }
*/ */
public String getPlatformType() { public String getPlatformType() {
return platformChainType; return platformChainType;

View File

@ -316,35 +316,29 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
final DeviceInfoReport deviceInfoReport, final DeviceInfoReport deviceInfoReport,
final PlatformCredential basePlatformCredential, final PlatformCredential basePlatformCredential,
final Map<PlatformCredential, SupplyChainValidation> deltaMapping) { final Map<PlatformCredential, SupplyChainValidation> deltaMapping) {
final String baseErrorMessage = "Can't validate delta platform"
+ "certificate attributes without ";
String message; String message;
if (deltaPlatformCredential == null) {
message = baseErrorMessage + "a delta platform certificate";
LOGGER.error(message);
return new AppraisalStatus(FAIL, message);
}
if (deviceInfoReport == null) {
message = baseErrorMessage + "a device info report";
LOGGER.error(message);
return new AppraisalStatus(FAIL, message);
}
if (basePlatformCredential == null) {
message = baseErrorMessage + "a base platform credential";
LOGGER.error(message);
return new AppraisalStatus(FAIL, message);
}
// this needs to be a loop for all deltas, link to issue #110
// check that they don't have the same serial number
for (PlatformCredential delta : deltaMapping.keySet()) {
if (!basePlatformCredential.getPlatformSerial() if (!basePlatformCredential.getPlatformSerial()
.equals(deltaPlatformCredential.getPlatformSerial())) { .equals(delta.getPlatformSerial())) {
message = String.format("Delta platform certificate " message = String.format("Base and Delta platform serial "
+ "platform serial number (%s) does not match " + "numbers do not match (%s != %s)",
+ "the base certificate's platform serial number (%s)", delta.getPlatformSerial(),
deltaPlatformCredential.getPlatformSerial(),
basePlatformCredential.getPlatformSerial()); basePlatformCredential.getPlatformSerial());
LOGGER.error(message); LOGGER.error(message);
return new AppraisalStatus(FAIL, message); return new AppraisalStatus(FAIL, message);
} }
// none of the deltas should have the serial number of the base
if (basePlatformCredential.getSerialNumber()
.equals(delta.getSerialNumber())) {
message = String.format("Delta Certificate with same serial number as base. (%s)",
delta.getSerialNumber());
LOGGER.error(message);
return new AppraisalStatus(FAIL, message);
}
}
// parse out the provided delta and its specific chain. // parse out the provided delta and its specific chain.
List<ComponentIdentifier> origPcComponents List<ComponentIdentifier> origPcComponents
@ -501,18 +495,14 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// check PlatformSerial against both system-serial-number and baseboard-serial-number // check PlatformSerial against both system-serial-number and baseboard-serial-number
fieldValidation = ( fieldValidation = (
( (optionalPlatformCredentialFieldNullOrMatches(
optionalPlatformCredentialFieldNullOrMatches(
"PlatformSerial", "PlatformSerial",
platformCredential.getPlatformSerial(), platformCredential.getPlatformSerial(),
hardwareInfo.getSystemSerialNumber()) hardwareInfo.getSystemSerialNumber()))
) || ( || (optionalPlatformCredentialFieldNullOrMatches(
optionalPlatformCredentialFieldNullOrMatches(
"PlatformSerial", "PlatformSerial",
platformCredential.getPlatformSerial(), platformCredential.getPlatformSerial(),
hardwareInfo.getBaseboardSerialNumber()) hardwareInfo.getBaseboardSerialNumber())));
)
);
if (!fieldValidation) { if (!fieldValidation) {
resultMessage.append("Platform serial did not match\n"); resultMessage.append("Platform serial did not match\n");
@ -755,8 +745,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
deltaMapping.put(delta, new SupplyChainValidation( deltaMapping.put(delta, new SupplyChainValidation(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL, SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
FAIL, certificateList, FAIL, certificateList,
failureMsg.toString() failureMsg.toString()));
)); builtMatchList.add(ci);
} }
} }
} }
@ -772,24 +762,18 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
String paccorOutputString = deviceInfoReport.getPaccorOutputString(); String paccorOutputString = deviceInfoReport.getPaccorOutputString();
String unmatchedComponents; String unmatchedComponents;
try { try {
// List<ComponentInfo> componentInfoList
// = getComponentInfoFromPaccorOutput(paccorOutputString);
// compare based on component class // compare based on component class
List<ComponentInfo> componentInfoList = getV2PaccorOutput(paccorOutputString); List<ComponentInfo> componentInfoList = getV2PaccorOutput(paccorOutputString);
// testComponentMatching(compMapping, chainCiMapping.values());
// this is what I want to rewrite // this is what I want to rewrite
// unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch(
// new LinkedList<>(chainCiMapping.values()),
// compMapping.keySet().stream().collect(Collectors.toList()));
unmatchedComponents = validateV2PlatformCredentialAttributes( unmatchedComponents = validateV2PlatformCredentialAttributes(
builtMatchList, builtMatchList,
componentInfoList); componentInfoList);
fieldValidation &= unmatchedComponents.isEmpty(); fieldValidation &= unmatchedComponents.isEmpty();
} catch (IOException e) { } catch (IOException ioEx) {
final String baseErrorMessage = "Error parsing JSON output from PACCOR: "; final String baseErrorMessage = "Error parsing JSON output from PACCOR: ";
LOGGER.error(baseErrorMessage + e.toString()); LOGGER.error(baseErrorMessage + ioEx.toString());
LOGGER.error("PACCOR output string:\n" + paccorOutputString); LOGGER.error("PACCOR output string:\n" + paccorOutputString);
return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage()); return new AppraisalStatus(ERROR, baseErrorMessage + ioEx.getMessage());
} }
if (!fieldValidation) { if (!fieldValidation) {
// instead of listing all unmatched, just print the #. The failure // instead of listing all unmatched, just print the #. The failure