[#72] Supply Chain Validator fix and update (#94)

* This fix correct an IllegalStateException for the SupplyChainValider when all policy settings are true.  When trying to remove a value from the iterator in the validator, the item was null and caused this issue.  This also takes out the Platform Serial as a required field.

Closes #72

* checking in a small change that puts back in a line for checking the serial number.  It has been changed from FAIL to PASS however.

* Committing updated changes.

* Committing test certs for changes.

* Updated unit tests

* Fixing travis checkstyle for URISyntaxException missing from UnitTests
This commit is contained in:
Cyrus 2019-02-25 10:37:11 -05:00 committed by apldev3
parent f2bee8f9cc
commit aeebd068f5
4 changed files with 132 additions and 22 deletions

View File

@ -142,6 +142,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* @param acceptExpired whether or not to accept expired certificates as valid. * @param acceptExpired whether or not to accept expired certificates as valid.
* @return The result of the validation. * @return The result of the validation.
*/ */
@Override
public AppraisalStatus validatePlatformCredential(final PlatformCredential pc, public AppraisalStatus validatePlatformCredential(final PlatformCredential pc,
final KeyStore trustStore, final KeyStore trustStore,
final boolean acceptExpired) { final boolean acceptExpired) {
@ -210,6 +211,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* identity request as the platform credential. * identity request as the platform credential.
* @return The result of the validation. * @return The result of the validation.
*/ */
@Override
public AppraisalStatus validatePlatformCredentialAttributes( public AppraisalStatus validatePlatformCredentialAttributes(
final PlatformCredential platformCredential, final PlatformCredential platformCredential,
final DeviceInfoReport deviceInfoReport, final DeviceInfoReport deviceInfoReport,
@ -397,12 +399,12 @@ 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 = (
( (
requiredPlatformCredentialFieldIsNonEmptyAndMatches( optionalPlatformCredentialFieldNullOrMatches(
"PlatformSerial", "PlatformSerial",
platformCredential.getPlatformSerial(), platformCredential.getPlatformSerial(),
hardwareInfo.getSystemSerialNumber()) hardwareInfo.getSystemSerialNumber())
) || ( ) || (
requiredPlatformCredentialFieldIsNonEmptyAndMatches( optionalPlatformCredentialFieldNullOrMatches(
"PlatformSerial", "PlatformSerial",
platformCredential.getPlatformSerial(), platformCredential.getPlatformSerial(),
hardwareInfo.getBaseboardSerialNumber()) hardwareInfo.getBaseboardSerialNumber())
@ -493,8 +495,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// on the leftovers in the lists and the policy in place. // on the leftovers in the lists and the policy in place.
final List<ComponentIdentifier> pcComponents = new ArrayList<>(); final List<ComponentIdentifier> pcComponents = new ArrayList<>();
for (ComponentIdentifier component : untrimmedPcComponents) { for (ComponentIdentifier component : untrimmedPcComponents) {
DERUTF8String componentSerial = null; DERUTF8String componentSerial = new DERUTF8String("");
DERUTF8String componentRevision = null; DERUTF8String componentRevision = new DERUTF8String("");
if (component.getComponentSerial() != null) { if (component.getComponentSerial() != null) {
componentSerial = new DERUTF8String( componentSerial = new DERUTF8String(
component.getComponentSerial().getString().trim()); component.getComponentSerial().getString().trim());
@ -605,15 +607,15 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// The remaining components from the manufacturer have only the 2 required fields so // The remaining components from the manufacturer have only the 2 required fields so
// just match them. // just match them.
Iterator<ComponentIdentifier> pcComponentIter = pcComponentsFromManufacturer.iterator(); List<ComponentIdentifier> templist = new ArrayList<>(pcComponentsFromManufacturer);
while (pcComponentIter.hasNext()) { for (ComponentIdentifier ci : templist) {
ComponentIdentifier pcComponent = pcComponentIter.next(); ComponentIdentifier pcComponent = ci;
Iterator<ComponentInfo> diComponentIter Iterator<ComponentInfo> diComponentIter
= deviceInfoComponentsFromManufacturer.iterator(); = deviceInfoComponentsFromManufacturer.iterator();
while (diComponentIter.hasNext()) { while (diComponentIter.hasNext()) {
ComponentInfo potentialMatch = diComponentIter.next(); ComponentInfo potentialMatch = diComponentIter.next();
if (isMatch(pcComponent, potentialMatch)) { if (isMatch(pcComponent, potentialMatch)) {
pcComponentIter.remove(); pcComponentsFromManufacturer.remove(ci);
diComponentIter.remove(); diComponentIter.remove();
} }
} }
@ -636,13 +638,12 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
return true; return true;
} }
/**
/** * Returns true if fieldValue is null or empty.
* Returns true if fieldValue is null or empty. * @param description description of the value
* @param description description of the value * @param fieldValue value of the field
* @param fieldValue value of the field * @return true if fieldValue is null or empty; false otherwise
* @return true if fieldValue is null or empty; false otherwise */
*/
private static boolean hasEmptyValueForRequiredField(final String description, private static boolean hasEmptyValueForRequiredField(final String description,
final String fieldValue) { final String fieldValue) {
if (StringUtils.isEmpty(fieldValue)) { if (StringUtils.isEmpty(fieldValue)) {
@ -669,6 +670,15 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
return false; return false;
} }
/**
* Validates the information supplied for the Platform Credential. This
* method checks if the field is required and therefore if the value is
* present then verifies that the values match.
* @param platformCredentialFieldName name of field to be compared
* @param platformCredentialFieldValue first value to compare
* @param otherValue second value to compare
* @return true if values match
*/
private static boolean requiredPlatformCredentialFieldIsNonEmptyAndMatches( private static boolean requiredPlatformCredentialFieldIsNonEmptyAndMatches(
final String platformCredentialFieldName, final String platformCredentialFieldName,
final String platformCredentialFieldValue, final String platformCredentialFieldValue,
@ -678,6 +688,35 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
return false; return false;
} }
return platformCredentialFieldMatches(platformCredentialFieldName,
platformCredentialFieldValue, otherValue);
}
/**
* Validates the information supplied for the Platform Credential. This
* method checks if the value is present then verifies that the values match.
* If not present, then returns true.
* @param platformCredentialFieldName name of field to be compared
* @param platformCredentialFieldValue first value to compare
* @param otherValue second value to compare
* @return true if values match or null
*/
private static boolean optionalPlatformCredentialFieldNullOrMatches(
final String platformCredentialFieldName,
final String platformCredentialFieldValue,
final String otherValue) {
if (platformCredentialFieldValue == null) {
return true;
}
return platformCredentialFieldMatches(platformCredentialFieldName,
platformCredentialFieldValue, otherValue);
}
private static boolean platformCredentialFieldMatches(
final String platformCredentialFieldName,
final String platformCredentialFieldValue,
final String otherValue) {
String trimmedFieldValue = platformCredentialFieldValue.trim(); String trimmedFieldValue = platformCredentialFieldValue.trim();
String trimmedOtherValue = otherValue.trim(); String trimmedOtherValue = otherValue.trim();
@ -692,6 +731,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
+ "a related field in the DeviceInfoReport (%s)", + "a related field in the DeviceInfoReport (%s)",
platformCredentialFieldName, trimmedFieldValue) platformCredentialFieldName, trimmedFieldValue)
); );
return true; return true;
} }
@ -812,6 +852,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* as valid. * as valid.
* @return the result of the validation. * @return the result of the validation.
*/ */
@Override
public AppraisalStatus validateEndorsementCredential(final EndorsementCredential ec, public AppraisalStatus validateEndorsementCredential(final EndorsementCredential ec,
final KeyStore trustStore, final KeyStore trustStore,
final boolean acceptExpired) { final boolean acceptExpired) {

View File

@ -93,6 +93,10 @@ import static org.powermock.api.mockito.PowerMockito.when;
public class SupplyChainCredentialValidatorTest { public class SupplyChainCredentialValidatorTest {
private static final String SAMPLE_PACCOR_OUTPUT_TXT = "sample_paccor_output.txt"; private static final String SAMPLE_PACCOR_OUTPUT_TXT = "sample_paccor_output.txt";
private static final String SAMPLE_PACCOR_OUTPUT_NOT_SPECIFIED_TXT
= "sample_paccor_output_not_specified_values.txt";
private static final String SAMPLE_TEST_PACCOR_CERT
= "/validation/platform_credentials_2/paccor_platform_cert.crt";
private static final String SAMPLE_PACCOR_OUTPUT_WITH_EXTRA_COMPONENT_TXT private static final String SAMPLE_PACCOR_OUTPUT_WITH_EXTRA_COMPONENT_TXT
= "sample_paccor_output_with_extra_component.txt"; = "sample_paccor_output_with_extra_component.txt";
@ -1382,6 +1386,11 @@ public class SupplyChainCredentialValidatorTest {
return setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_TXT); return setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_TXT);
} }
private static DeviceInfoReport setupDeviceInfoReportWithNotSpecifiedComponents()
throws IOException {
return setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_NOT_SPECIFIED_TXT);
}
private static DeviceInfoReport setupDeviceInfoReportWithComponents( private static DeviceInfoReport setupDeviceInfoReportWithComponents(
final String paccorOutputResource) throws IOException { final String paccorOutputResource) throws IOException {
DeviceInfoReport deviceInfoReport = setupDeviceInfoReport(); DeviceInfoReport deviceInfoReport = setupDeviceInfoReport();
@ -1464,11 +1473,19 @@ public class SupplyChainCredentialValidatorTest {
deviceInfoReport.getPaccorOutputString()); deviceInfoReport.getPaccorOutputString());
List<ComponentIdentifier> componentIdentifierList = new ArrayList<>(); List<ComponentIdentifier> componentIdentifierList = new ArrayList<>();
for (ComponentInfo deviceInfoComponent : deviceInfoComponents) { for (ComponentInfo deviceInfoComponent : deviceInfoComponents) {
DERUTF8String serial = null;
DERUTF8String revision = null;
if (deviceInfoComponent.getComponentSerial() != null) {
serial = new DERUTF8String(deviceInfoComponent.getComponentSerial());
}
if (deviceInfoComponent.getComponentRevision() != null) {
revision = new DERUTF8String(deviceInfoComponent.getComponentRevision());
}
componentIdentifierList.add(new ComponentIdentifier( componentIdentifierList.add(new ComponentIdentifier(
new DERUTF8String(deviceInfoComponent.getComponentManufacturer()), new DERUTF8String(deviceInfoComponent.getComponentManufacturer()),
new DERUTF8String(deviceInfoComponent.getComponentModel()), new DERUTF8String(deviceInfoComponent.getComponentModel()),
new DERUTF8String(deviceInfoComponent.getComponentSerial()), serial,
new DERUTF8String(deviceInfoComponent.getComponentRevision()), revision,
null, null,
ASN1Boolean.TRUE, ASN1Boolean.TRUE,
Collections.emptyList() Collections.emptyList()
@ -1487,7 +1504,7 @@ public class SupplyChainCredentialValidatorTest {
* @throws IOException if unable to set up DeviceInfoReport from resource file * @throws IOException if unable to set up DeviceInfoReport from resource file
*/ */
@Test @Test
public final void testvalidatePlatformCredentialAttributesV2p0NoComponentsPass() public final void testValidatePlatformCredentialAttributesV2p0NoComponentsPass()
throws IOException { throws IOException {
DeviceInfoReport deviceInfoReport = setupDeviceInfoReport(); DeviceInfoReport deviceInfoReport = setupDeviceInfoReport();
PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport);
@ -1505,7 +1522,7 @@ public class SupplyChainCredentialValidatorTest {
* @throws IOException if unable to set up DeviceInfoReport from resource file * @throws IOException if unable to set up DeviceInfoReport from resource file
*/ */
@Test @Test
public final void testvalidatePlatformCredentialAttributesV2p0WithComponentsPass() public final void testValidatePlatformCredentialAttributesV2p0WithComponentsPass()
throws IOException { throws IOException {
DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents();
PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport);
@ -1538,6 +1555,26 @@ public class SupplyChainCredentialValidatorTest {
SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID); SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID);
} }
/**
* Tests that TPM 2.0 Platform Credentials validate correctly against the device info report
* when there are components present, and when the PlatformSerial field holds the system's
* serial number instead of the baseboard serial number.
* @throws IOException if unable to set up DeviceInfoReport from resource file
* @throws URISyntaxException failed to read certificate
*/
@Test
public final void testValPCAttributesV2p0WithComponentsPassPlatformSerialWithSystemSerial2()
throws IOException, URISyntaxException {
DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithNotSpecifiedComponents();
PlatformCredential platformCredential = new PlatformCredential(
Files.readAllBytes(Paths.get(CertificateTest.class.
getResource((SAMPLE_TEST_PACCOR_CERT)).toURI())));
AppraisalStatus appraisalStatus = SupplyChainCredentialValidator
.validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport);
Assert.assertEquals(appraisalStatus.getAppStatus(), AppraisalStatus.Status.FAIL);
}
/** /**
* Tests that the SupplyChainCredentialValidator fails when required fields are null. * Tests that the SupplyChainCredentialValidator fails when required fields are null.
* @throws IOException if unable to set up DeviceInfoReport from resource file * @throws IOException if unable to set up DeviceInfoReport from resource file
@ -1586,9 +1623,7 @@ public class SupplyChainCredentialValidatorTest {
result = SupplyChainCredentialValidator result = SupplyChainCredentialValidator
.validatePlatformCredentialAttributesV2p0(platformCredential, .validatePlatformCredentialAttributesV2p0(platformCredential,
deviceInfoReport); deviceInfoReport);
Assert.assertEquals(result.getAppStatus(), AppraisalStatus.Status.FAIL); Assert.assertEquals(result.getAppStatus(), AppraisalStatus.Status.PASS);
Assert.assertEquals(result.getMessage(), "Platform serial did not match\n");
platformCredential = setupMatchingPlatformCredential(deviceInfoReport); platformCredential = setupMatchingPlatformCredential(deviceInfoReport);
result = SupplyChainCredentialValidator result = SupplyChainCredentialValidator
.validatePlatformCredentialAttributesV2p0(platformCredential, .validatePlatformCredentialAttributesV2p0(platformCredential,

View File

@ -0,0 +1,34 @@
{
"PLATFORM": {
"PLATFORMMANUFACTURERSTR": "Not Specified","PLATFORMMODEL": "Not Specified","PLATFORMVERSION": "Not Specified"
},
"COMPONENTS": [
{
"MANUFACTURER": "Not Specified","MODEL": "Not Specified"
},
{
"MANUFACTURER": "Not Specified","MODEL": "Not Specified","FIELDREPLACEABLE": "false"
},
{
"MANUFACTURER": "Not Specified","MODEL": "UEFI"
},
{
"MANUFACTURER": "Broadcom Inc. and subsidiaries","MODEL": "NetXtreme BCM5722 Gigabit Ethernet PCI Express","FIELDREPLACEABLE": "true","REVISION": "00"
},
{
"MANUFACTURER": "Intel Corporation","MANUFACTURERID": "1.3.6.1.4.1.343","MODEL": "Ethernet Connection (2) I219-LM","FIELDREPLACEABLE": "true","REVISION": "31"
}
],
"PROPERTIES": [
{
"NAME": "uname -r",
"VALUE": "3.10.0-957.1.3.el7.x86_64"
},
{
"NAME": "OS Release",
"VALUE": "CentOS Linux 7 (Core)"
}
]
}