Added Pci IDs translate to the HIRS_Util module for the supply chain validator process so that the hash can match up for highlighting failed components.

This commit is contained in:
Cyrus 2021-12-03 16:01:04 -05:00
parent a5c5a3ac60
commit 6337367ba9
4 changed files with 203 additions and 2 deletions

View File

@ -39,6 +39,7 @@ dependencies {
compile libs.joda_time
compile libs.log4j2
compile libs.mariadb
compile libs.pci_ids
compile libs.reflections
compile libs.guava
compile libs.spring_core
@ -48,6 +49,7 @@ dependencies {
exclude group: 'junit'
}
compile 'org.jboss.logging:jboss-logging:3.2.0.Final'
compile 'org.apache.commons:commons-text:1.9'
// add spring plugin, but do not pull transitive dependencies (causes conflicts)
compile(libs.spring_plugin) {

View File

@ -15,7 +15,7 @@ import hirs.data.persist.TPMReport;
import hirs.data.persist.baseline.TpmBlackListBaseline;
import hirs.data.persist.baseline.TpmWhiteListBaseline;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@ -0,0 +1,194 @@
package hirs.utils;
import com.github.marandus.pciid.model.Device;
import com.github.marandus.pciid.model.Vendor;
import com.github.marandus.pciid.service.PciIdsDatabase;
import com.google.common.base.Strings;
import hirs.data.persist.certificate.attributes.ComponentIdentifier;
import hirs.data.persist.certificate.attributes.V2.ComponentIdentifierV2;
import org.bouncycastle.asn1.DERUTF8String;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
/**
* Provide Java access to PCI IDs.
*/
public final class PciIds {
/**
* This pci ids file can be in different places on different distributions.
*/
public static final List<String> PCI_IDS_PATH =
Collections.unmodifiableList(new Vector<String>() {
private static final long serialVersionUID = 1L;
{
add("/usr/share/hwdata/pci.ids");
add("/usr/share/misc/pci.ids");
add("/tmp/pci.ids");
}
});
/**
* The PCI IDs Database object.
*
* This only needs to be loaded one time.
*
* The pci ids library protects the data inside the object by making it immutable.
*/
public static final PciIdsDatabase DB = new PciIdsDatabase();
static {
if (!DB.isReady()) {
String dbFile = null;
for (final String path : PCI_IDS_PATH) {
if ((new File(path)).exists()) {
dbFile = path;
break;
}
}
if (dbFile != null) {
InputStream is = null;
try {
is = new FileInputStream(new File(dbFile));
DB.loadStream(is);
} catch (IOException e) {
// DB will not be ready, hardware IDs will not be translated
dbFile = null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
dbFile = null;
}
}
}
}
}
}
/**
* Utility class.
*/
private PciIds() {
}
/**
* The Component Class TCG Registry OID.
*/
public static final String COMPCLASS_TCG_OID = "2.23.133.18.3.1";
/**
* The Component Class Value mask for NICs.
*/
public static final String COMPCLASS_TCG_CAT_NIC = "00090000";
/**
* The Component Class Value mask for GFX cards.
*/
public static final String COMPCLASS_TCG_CAT_GFX = "00050000";
/**
* Iterate through all components and translate PCI hardware IDs as necessary. It will only
* translate ComponentIdentifierV2+ objects as it relies on Component Class information.
* @param components List of ComponentIdentifiers.
* @return the translated list of ComponentIdentifiers.
*/
public static List<ComponentIdentifier> translate(
final List<ComponentIdentifier> components) {
Vector<ComponentIdentifier> newList = new Vector<ComponentIdentifier>();
if (components != null && !components.isEmpty()) {
for (final ComponentIdentifier component : components) {
// V2 components should not be found alongside V1 components
// they pass through just in case
if (component.isVersion2()) {
newList.add(translate((ComponentIdentifierV2) component));
} else {
newList.add(component);
}
}
}
return newList;
}
/**
* Translate Vendor and Device IDs, if found, in ComponentIdentifierV2 objects.
* It will only translate ID values, any other value will pass through.
* @param component ComponentIdentifierV2 object.
* @return the translated ComponentIdentifierV2 object.
*/
public static ComponentIdentifierV2 translate(final ComponentIdentifierV2 component) {
ComponentIdentifierV2 newComponent = null;
if (component != null) {
newComponent = component;
// This can be updated as we get more accurate component class registries and values
// Component Class Registry not accessible: TCG assumed
final String compClassValue = component.getComponentClass().getCategoryValue();
if (compClassValue.equals(COMPCLASS_TCG_CAT_NIC)
|| compClassValue.equals(COMPCLASS_TCG_CAT_GFX)) {
DERUTF8String manufacturer = translateVendor(component.getComponentManufacturer());
DERUTF8String model = translateDevice(component.getComponentManufacturer(),
component.getComponentModel());
newComponent = new ComponentIdentifierV2(component.getComponentClass(),
manufacturer,
model,
component.getComponentSerial(),
component.getComponentRevision(),
component.getComponentManufacturerId(),
component.getFieldReplaceable(),
component.getComponentAddress(),
component.getCertificateIdentifier(),
component.getComponentPlatformUri(),
component.getAttributeStatus());
}
}
return newComponent;
}
/**
* Look up the vendor name from the PCI IDs list, if the input string contains an ID.
* If any part of this fails, return the original manufacturer value.
* @param refManufacturer DERUTF8String, likely from a ComponentIdentifier
* @return DERUTF8String with the discovered vendor name, or the original manufacturer value.
*/
public static DERUTF8String translateVendor(final DERUTF8String refManufacturer) {
DERUTF8String manufacturer = refManufacturer;
if (manufacturer != null && manufacturer.getString().trim().matches("^[0-9A-Fa-f]{4}$")) {
Vendor ven = DB.findVendor(manufacturer.getString().toLowerCase());
if (ven != null && !Strings.isNullOrEmpty(ven.getName())) {
manufacturer = new DERUTF8String(ven.getName());
}
}
return manufacturer;
}
/**
* Look up the device name from the PCI IDs list, if the input strings contain IDs.
* The Device lookup requires the Vendor ID AND the Device ID to be valid values.
* If any part of this fails, return the original model value.
* @param refManufacturer DERUTF8String, likely from a ComponentIdentifier
* @param refModel DERUTF8String, likely from a ComponentIdentifier
* @return DERUTF8String with the discovered device name, or the original model value.
*/
public static DERUTF8String translateDevice(final DERUTF8String refManufacturer,
final DERUTF8String refModel) {
DERUTF8String manufacturer = refManufacturer;
DERUTF8String model = refModel;
if (manufacturer != null
&& model != null
&& manufacturer.getString().trim().matches("^[0-9A-Fa-f]{4}$")
&& model.getString().trim().matches("^[0-9A-Fa-f]{4}$")) {
Device dev = DB.findDevice(manufacturer.getString().toLowerCase(),
model.getString().toLowerCase());
if (dev != null && !Strings.isNullOrEmpty(dev.getName())) {
model = new DERUTF8String(dev.getName());
}
}
return model;
}
}

View File

@ -13,6 +13,7 @@ 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 hirs.utils.PciIds;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
@ -565,7 +566,11 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// pass information of which ones failed in additionInfo
for (ComponentIdentifier ci : validPcComponents) {
additionalInfo.append(String.format("%d;", ci.hashCode()));
ComponentIdentifierV2 pciCi = (ComponentIdentifierV2) ci;
if (PciIds.DB.isReady()) {
pciCi = PciIds.translate((ComponentIdentifierV2) ci);
}
additionalInfo.append(String.format("%d;", pciCi.hashCode()));
}
}