Move part of PciIds from AttestationCA back to Utils (#796)

* update pciids to acapciids throughout code

* add pciids to utils and update classes that use it

* moved the 4 vendor/device translate functions to the utils pciids

* added pciids translations to SPDM Device Context file

* cleaning up imports

* cleaning up comments

* cleaned up a few checkstyle warnings

* working to get class code

* update output message in main

* working on class code

* fixes/minor changes

* fixed check of class code list
This commit is contained in:
D2B8CA1B27286366A8607B6858C0565962613D18D0546480078B520CD7AD705A 2024-07-22 06:01:54 -04:00 committed by chubtub
parent 28d08812fd
commit 412fca8376
9 changed files with 228 additions and 145 deletions

View File

@ -0,0 +1,129 @@
package hirs.attestationca.persist.util;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.asn1.DERUTF8String;
import java.util.ArrayList;
import java.util.List;
import static hirs.utils.PciIds.translateDevice;
import static hirs.utils.PciIds.translateVendor;
/**
* Provide Java access to PCI IDs.
*/
@Log4j2
public final class AcaPciIds {
/**
* 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) {
List<ComponentIdentifier> newList = new ArrayList<>();
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;
}
/**
* Iterate through all components and translate PCI hardware IDs as necessary. It will only
* translate ComponentResults objects as it relies on Component Class information.
* @param componentResults List of ComponentResults.
* @return the translated list of ComponentResults.
*/
public static List<ComponentResult> translateResults(final List<ComponentResult> componentResults) {
List<ComponentResult> newList = new ArrayList<>();
if (componentResults != null && !componentResults.isEmpty()) {
for (final ComponentResult componentResult : componentResults) {
newList.add(translateResult(componentResult));
}
}
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().getCategory();
if (compClassValue.equals(COMPCLASS_TCG_CAT_NIC)
|| compClassValue.equals(COMPCLASS_TCG_CAT_GFX)) {
DERUTF8String manufacturer = (DERUTF8String) translateVendor(
component.getComponentManufacturer());
DERUTF8String model = (DERUTF8String) 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;
}
/**
* Translate Vendor and Device IDs, if found, in ComponentResult objects.
* It will only translate ID values, any other value will pass through.
* @param componentResult ComponentResult object.
* @return the translated ComponentResult object.
*/
public static ComponentResult translateResult(final ComponentResult componentResult) {
ComponentResult newComponent = null;
if (componentResult != null) {
newComponent = componentResult;
newComponent.setManufacturer(translateVendor(componentResult.getManufacturer()));
newComponent.setModel(translateDevice(componentResult.getManufacturer(),
componentResult.getModel()));
}
return newComponent;
}
}

View File

@ -13,7 +13,8 @@ import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.util.PciIds;
import hirs.attestationca.persist.util.AcaPciIds;
import hirs.utils.PciIds;
import hirs.utils.enums.DeviceInfoEnums;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.digest.DigestUtils;
@ -446,7 +447,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
fullDeltaChainComponents.clear();
for (ComponentIdentifier ci : subCompIdList) {
if (ci.isVersion2() && PciIds.DB.isReady()) {
ci = PciIds.translate((ComponentIdentifierV2) ci);
ci = AcaPciIds.translate((ComponentIdentifierV2) ci);
}
log.error("Unmatched component: " + ci);
fullDeltaChainComponents.add(ci);
@ -608,7 +609,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
for (ComponentIdentifier unmatchedComponent : pcUnmatchedComponents) {
if (unmatchedComponent.isVersion2() && PciIds.DB.isReady()) {
unmatchedComponent =
PciIds.translate((ComponentIdentifierV2) unmatchedComponent);
AcaPciIds.translate((ComponentIdentifierV2) unmatchedComponent);
}
log.error("Unmatched component " + unmatchedComponentCounter++ + ": "
+ unmatchedComponent);

View File

@ -12,8 +12,9 @@ import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestati
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
import hirs.attestationca.persist.util.PciIds;
import hirs.attestationca.persist.util.AcaPciIds;
import hirs.utils.BouncyCastleUtils;
import hirs.utils.PciIds;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@ -372,7 +373,7 @@ public final class CertificateStringMapBuilder {
certificate.getSerialNumber().toString(),
certificate.getPlatformSerial());
if (PciIds.DB.isReady()) {
compResults = PciIds.translateResults(compResults);
compResults = AcaPciIds.translateResults(compResults);
}
data.put("componentResults", compResults);
@ -382,7 +383,7 @@ public final class CertificateStringMapBuilder {
//Component Identifier - attempt to translate hardware IDs
List<ComponentIdentifier> comps = platformConfiguration.getComponentIdentifier();
if (PciIds.DB.isReady()) {
comps = PciIds.translate(comps);
comps = AcaPciIds.translate(comps);
}
data.put("componentsIdentifier", comps);
//Component Identifier URI

View File

@ -38,6 +38,7 @@ dependencies {
implementation libs.commons.lang3
implementation libs.commons.io
implementation libs.minimal.json
implementation libs.pci
implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
implementation 'org.apache.logging.log4j:log4j-api:2.19.0'

View File

@ -1,13 +1,12 @@
package hirs.attestationca.persist.util;
package hirs.utils;
import com.github.marandus.pciid.model.Device;
import com.github.marandus.pciid.model.DeviceClass;
import com.github.marandus.pciid.model.DeviceSubclass;
import com.github.marandus.pciid.model.ProgramInterface;
import com.github.marandus.pciid.model.Vendor;
import com.github.marandus.pciid.service.PciIdsDatabase;
import com.google.common.base.Strings;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.asn1.ASN1UTF8String;
import org.bouncycastle.asn1.DERUTF8String;
@ -25,6 +24,7 @@ import java.util.List;
*/
@Log4j2
public final class PciIds {
/**
* This pci ids file can be in different places on different distributions.
*/
@ -78,114 +78,6 @@ public final class 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) {
List<ComponentIdentifier> newList = new ArrayList<>();
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;
}
/**
* Iterate through all components and translate PCI hardware IDs as necessary. It will only
* translate ComponentResults objects as it relies on Component Class information.
* @param componentResults List of ComponentResults.
* @return the translated list of ComponentResults.
*/
public static List<ComponentResult> translateResults(final List<ComponentResult> componentResults) {
List<ComponentResult> newList = new ArrayList<>();
if (componentResults != null && !componentResults.isEmpty()) {
for (final ComponentResult componentResult : componentResults) {
newList.add(translateResult(componentResult));
}
}
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().getCategory();
if (compClassValue.equals(COMPCLASS_TCG_CAT_NIC)
|| compClassValue.equals(COMPCLASS_TCG_CAT_GFX)) {
DERUTF8String manufacturer = (DERUTF8String) translateVendor(
component.getComponentManufacturer());
DERUTF8String model = (DERUTF8String) 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;
}
/**
* Translate Vendor and Device IDs, if found, in ComponentResult objects.
* It will only translate ID values, any other value will pass through.
* @param componentResult ComponentResult object.
* @return the translated ComponentResult object.
*/
public static ComponentResult translateResult(final ComponentResult componentResult) {
ComponentResult newComponent = null;
if (componentResult != null) {
newComponent = componentResult;
newComponent.setManufacturer(translateVendor(componentResult.getManufacturer()));
newComponent.setModel(translateDevice(componentResult.getManufacturer(),
componentResult.getModel()));
}
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.
@ -229,7 +121,7 @@ public final class PciIds {
* @return ASN1UTF8String with the discovered device name, or the original model value.
*/
public static ASN1UTF8String translateDevice(final ASN1UTF8String refManufacturer,
final ASN1UTF8String refModel) {
final ASN1UTF8String refModel) {
ASN1UTF8String manufacturer = refManufacturer;
ASN1UTF8String model = refModel;
if (manufacturer != null
@ -268,4 +160,44 @@ public final class PciIds {
}
return model;
}
/**
* Look up the device class 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 refClassCode String, formatted as 2 characters (1 byte) for each of the 3 categories
* Example "010802":
* Class: "01"
* Subclass: "08"
* Programming Interface: "02"
* @return List<String> 3-element list with the class code
* 1st element: human-readable description of Class
* 2nd element: human-readable description of Subclass
* 3rd element: human-readable description of Programming Interface
*/
public static List<String> translateDeviceClass(final String refClassCode) {
List<String> translatedClassCode = new ArrayList<>();
String classCode = refClassCode;
if (classCode != null && classCode.trim().matches("^[0-9A-Fa-f]{6}$")) {
String deviceClass = classCode.substring(0,2).toLowerCase();
String deviceSubclass = classCode.substring(2,4).toLowerCase();
String programInterface = classCode.substring(4,6).toLowerCase();
translatedClassCode.add(deviceClass);
translatedClassCode.add(deviceSubclass);
translatedClassCode.add(programInterface);
DeviceClass devC = DB.findDeviceClass(deviceClass);
DeviceSubclass devSc = DB.findDeviceSubclass(deviceClass, deviceSubclass);
ProgramInterface progI = DB.findProgramInterface(deviceClass, deviceSubclass, programInterface);
if (devC != null && !Strings.isNullOrEmpty(devC.getName())) {
translatedClassCode.set(0, devC.getName());
}
if (devSc != null && !Strings.isNullOrEmpty(devSc.getName())) {
translatedClassCode.set(1, devSc.getName());
}
if (progI != null && !Strings.isNullOrEmpty(progI.getName())) {
translatedClassCode.set(2, progI.getName());
}
}
return translatedClassCode;
}
}

View File

@ -3,6 +3,13 @@ package hirs.utils.tpm.eventlog.events;
import hirs.utils.HexUtils;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
import static hirs.utils.PciIds.translateDevice;
import static hirs.utils.PciIds.translateDeviceClass;
import static hirs.utils.PciIds.translateVendor;
/**
* Class to process the DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT event per PFP.
* <p>
@ -99,21 +106,30 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
}
/**
* Returns a human readable description of the data within this structure.
* Returns a human-readable description of the data within this structure.
*
* @return a description of this structure..
* @return a description of this structure.
*/
public String toString() {
String dSEDpciContextInfo = "";
dSEDpciContextInfo += super.toString();
dSEDpciContextInfo += "\n Device Type = PCI";
dSEDpciContextInfo += "\n VendorID = 0x" + vendorId;
dSEDpciContextInfo += "\n DeviceID = 0x" + deviceId;
dSEDpciContextInfo += "\n RevisionID = 0x" + revisionId;
dSEDpciContextInfo += "\n ClassCode = 0x" + classCode;
dSEDpciContextInfo += "\n SubsystemVendorID = 0x" + subsystemVendorId;
dSEDpciContextInfo += "\n SubsystemID = 0x" + subsystemId;
dSEDpciContextInfo += "\n Vendor = " + translateVendor(vendorId);
dSEDpciContextInfo += "\n Device = " + translateDevice(vendorId, deviceId);
dSEDpciContextInfo += "\n RevisionID = " + revisionId;
List<String> classCodeList = translateDeviceClass(classCode);
dSEDpciContextInfo += "\n Device Class: ";
if(classCodeList.size() == 3) {
dSEDpciContextInfo += "\n Class = " + classCodeList.get(0);
dSEDpciContextInfo += "\n Subclass = " + classCodeList.get(1);
dSEDpciContextInfo += "\n Programming Interface = " + classCodeList.get(2);
} else {
dSEDpciContextInfo += " ** Class code could not be determined **";
}
dSEDpciContextInfo += "\n SubsystemVendor = " + translateVendor(subsystemVendorId);
dSEDpciContextInfo += "\n Subsystem = " + translateDevice(subsystemVendorId, subsystemId);
return dSEDpciContextInfo;
}

View File

@ -208,7 +208,7 @@ public abstract class DeviceSecurityEventHeader {
dsedHeaderCommonInfo += "\n SPDM Device Type = " + deviceTypeToString(deviceType);
if (devicePathValid) {
dsedHeaderCommonInfo += "\n SPDM Device Path =\n";
dsedHeaderCommonInfo += "\n SPDM Device Path:\n";
dsedHeaderCommonInfo += devicePath;
}
else {

View File

@ -116,7 +116,7 @@ public class UefiDevicePath {
*/
private String processDev(final byte[] path, final int offset)
throws UnsupportedEncodingException {
String devInfo = " ";
String devInfo = " ";
int devPath = path[offset];
byte unknownSubType = path[offset + UefiConstants.OFFSET_1];
switch (path[0 + offset]) {

View File

@ -27,7 +27,12 @@ final class Main {
private static Commander commander = null;
private static FileOutputStream outputStream = null;
private static byte[] eventLog = null;
private static boolean bContentFlag, bEventFlag, bHexEvent, bHexFlag, bPcrFlag = false;
private static boolean bContentFlag = false;
private static boolean bEventFlag = false;
private static boolean bHexEvent = false;
private static boolean bHexFlag = false;
private static boolean bPcrFlag = false;
/**
* Main Constructor.
@ -131,17 +136,13 @@ final class Main {
+ evLog.getEventList().size() + " events:\n\n");
}
if (evLog.getVendorTableFileStatus() == FILESTATUS_NOT_ACCESSIBLE) {
writeOut("*** WARNING: The file vendor-table.json file was not accessible so data " +
"in some Secure Boot PCR 7 events cannot be processed.\n\n");
}
else if (evLog.getVendorTableFileStatus() == FILESTATUS_FROM_CODE) {
writeOut("*** NOTE: " +
"The file vendor-table.json file was not accessible from the filesystem,\n" +
" so the vendor-table.json from code was " +
"used. If updates were made in the\n" +
" filesystem file, they will not be reflected. " +
"This affects parsing in some\n" +
" Secure Boot PCR 7 events.\n\n");
writeOut("*** WARNING: The file vendor-table.json was not accessible from the "
+ "filesystem or the code, so some event data shown in the output of this "
+ "tool may be outdated or omitted.\n\n");
} else if (evLog.getVendorTableFileStatus() == FILESTATUS_FROM_CODE) {
writeOut("*** NOTE: "
+ "The file vendor-table.json file was not accessible from the filesystem,\n"
+ " so the vendor-table.json from code was used.\n\n");
}
}
int eventCount = 0;
@ -189,7 +190,8 @@ final class Main {
* @return a byte array holding the entire log
*/
public static byte[] openLog(final String fileName) {
String os = System.getProperty("os.name").toLowerCase(), fName = fileName;
String os = System.getProperty("os.name").toLowerCase();
String fName = fileName;
byte[] rawLog = null;
boolean bDefault = false;
bHexFlag = commander.getHexFlag();
@ -248,7 +250,8 @@ final class Main {
* @return A sting containing human readable results.
*/
public static String compareLogs(final String logFileName1, final String logFileName2) {
TCGEventLog eventLog1 = null, eventLog2 = null;
TCGEventLog eventLog1 = null;
TCGEventLog eventLog2 = null;
byte[] evLog = openLog(logFileName1);
byte[] evLog2 = openLog(logFileName2);
StringBuilder sb = new StringBuilder();
@ -337,7 +340,7 @@ final class Main {
*
* @param eventLog The Reference Event log.
* @param event single event to match.
* @return
* @return indicator whether match was found.
*/
private static boolean digestMatch(final Collection<TpmPcrEvent> eventLog,
final TpmPcrEvent event) {