Merge pull request #778 from nsacyber/v3_issue_768_Part2-eventProcessing

Event processing when no access to vendor-table.json Part 2
This commit is contained in:
iadgovuser26 2024-06-17 13:16:30 -04:00 committed by GitHub
commit 78d85bddfd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 232 additions and 11 deletions

View File

@ -124,7 +124,7 @@ ospackage {
// copy json tables
into ('/etc/hirs/aca/default-properties') {
from '../HIRS_AttestationCA/src/main/resources/component-class.json'
from '../HIRS_AttestationCA/src/main/resources/vendor-table.json'
from '../HIRS_Utils/src/main/resources/vendor-table.json'
}
// copy springboot property file
into ('/etc/hirs/aca/') {

View File

@ -97,4 +97,75 @@ public final class JsonUtils {
return jsonObject;
}
/**
* Getter for the JSON Object that is associated with the elementName value
* mapped in the associated JSON file.
* Default {@link java.nio.charset.Charset} is UTF 8
*
* @param jsonFilename the object holding the name of the file in classpath to parse.
* @param elementName the specific object to pull from the file
* @return a JSON object
*/
public static JsonObject getSpecificJsonObject(final String jsonFilename, final String elementName) {
// find the file and load it
return getSpecificJsonObject(jsonFilename, elementName, StandardCharsets.UTF_8);
}
/**
* Getter for the JSON Object that is associated with the elementName value
* mapped in the associated JSON file.
* Default {@link java.nio.charset.Charset} is UTF 8
*
* @param jsonFilename the object holding the name of the file in classpath to parse.
* @param elementName the specific object to pull from the file
* @param charset the character set to use
* @return a JSON object
*/
public static JsonObject getSpecificJsonObject(final String jsonFilename,
final String elementName,
final Charset charset) {
// find the file and load it
JsonObject jsonObject = getJsonObject(jsonFilename, charset);
if (jsonObject != null && jsonObject.get(elementName) != null) {
return jsonObject.get(elementName).asObject();
}
return new JsonObject();
}
/**
* Getter for the JSON Object that is mapped in the associated JSON file.
* Default {@link java.nio.charset.Charset} is UTF 8
*
* @param jsonFilename the object holding the name of the file in classpath to parse.
* @return a JSON object
*/
public static JsonObject getJsonObject(final String jsonFilename) {
return getJsonObject(jsonFilename, StandardCharsets.UTF_8);
}
/**
* Getter for the JSON Object that is mapped in the associated JSON file.
*
* @param jsonFilename the object holding the name of the file in classpath to parse.
* @param charset the character set to use
* @return a JSON object
*/
public static JsonObject getJsonObject(final String jsonFilename, final Charset charset) {
JsonObject jsonObject = new JsonObject();
InputStream jsonIs = JsonUtils.class.getClassLoader().getResourceAsStream(jsonFilename);
if (jsonIs != null) {
try {
jsonObject = Json.parse(new InputStreamReader(jsonIs,
charset)).asObject();
} catch (IOException ex) {
jsonObject = new JsonObject();
}
}
return jsonObject;
}
}

View File

@ -20,6 +20,9 @@ import java.security.cert.CertificateException;
import java.util.Collection;
import java.util.LinkedHashMap;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_FROM_FILESYSTEM;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIBLE;
/**
* Class for handling different formats of TCG Event logs.
*/
@ -77,6 +80,15 @@ public final class TCGEventLog {
/** Event Output Flag use. */
@Getter
private boolean bCryptoAgile = false;
/**
* Track status of vendor-table.json
* This is only used if there is an event that uses a UefiVariable data structure.
* Default is normal status (normal status is from-filesystem).
* Status will only change IF there is a UefiVariable event in this log,
* and if that event causes a different status.
*/
@Getter
private String vendorTableFileStatus = FILESTATUS_FROM_FILESYSTEM;
/**
* Default blank object constructor.
@ -147,6 +159,20 @@ public final class TCGEventLog {
} else {
eventList.put(eventNumber, new TpmPcrEvent1(is, eventNumber++));
}
// first check if any previous event has not been able to access vendor-table.json,
// and if that is the case, the first comparison in the if returns false and
// the if statement is not executed
// [previous event file status = vendorTableFileStatus]
// (ie. keep the file status to reflect that file was not accessible at some point)
// next, check if the new event has any status other than the default 'filesystem',
// and if that is the case, the 2nd comparison in the if returns true and
// the if statement is executed
// [new event file status = eventList.get(eventNumber-1).getVendorTableFileStatus()]
// (ie. if the new file status is not-accessible or from-code, then want to update)
if((vendorTableFileStatus != FILESTATUS_NOT_ACCESSIBLE) &&
(eventList.get(eventNumber-1).getVendorTableFileStatus() != FILESTATUS_FROM_FILESYSTEM)) {
vendorTableFileStatus = eventList.get(eventNumber-1).getVendorTableFileStatus();
}
}
calculatePcrValues();
}

View File

@ -33,6 +33,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_FROM_FILESYSTEM;
/**
* Class to process a TCG_PCR_EVENT.
* TCG_PCR_EVENT is used when the Event log uses the SHA1 Format as described in the
@ -117,6 +119,16 @@ public class TpmPcrEvent {
@Setter @Getter
private boolean error = false;
/**
* Track status of vendor-table.json
* This is only used for events that use a UefiVariable data structure.
* Default is normal status (normal status is from-filesystem).
* Status will only change IF this is an event that has a UefiVariable,
* and if that event causes a different status.
*/
@Getter
private String vendorTableFileStatus = FILESTATUS_FROM_FILESYSTEM;
/**
* Constructor.
*
@ -508,9 +520,12 @@ public class TpmPcrEvent {
String efiVarDescription = efiVar.toString().replace("\n", "\n ");
description += "Event Content:\n " + efiVarDescription.substring(0,
efiVarDescription.length() - INDENT_3);
vendorTableFileStatus = efiVar.getVendorTableFileStatus();
break;
case EvConstants.EV_EFI_VARIABLE_BOOT:
description += "Event Content:\n" + new UefiVariable(content).toString();
UefiVariable efiVarBoot = new UefiVariable(content);
description += "Event Content:\n" + efiVarBoot.toString();
vendorTableFileStatus = efiVarBoot.getVendorTableFileStatus();
break;
case EvConstants.EV_EFI_BOOT_SERVICES_APPLICATION:
EvEfiBootServicesApp bootServices = new EvEfiBootServicesApp(content);
@ -539,7 +554,9 @@ public class TpmPcrEvent {
case EvConstants.EV_EFI_HCRTM_EVENT:
break;
case EvConstants.EV_EFI_VARIABLE_AUTHORITY:
description += "Event Content:\n" + new UefiVariable(content).toString();
UefiVariable efiVarAuth = new UefiVariable(content);
description += "Event Content:\n" + efiVarAuth.toString();
vendorTableFileStatus = efiVarAuth.getVendorTableFileStatus();
break;
case EvConstants.EV_EFI_SPDM_FIRMWARE_BLOB:
description += "Event Content:\n" + new EvEfiSpdmFirmwareBlob(content).toString();

View File

@ -23,7 +23,7 @@ import java.nio.charset.StandardCharsets;
* NUL-terminated, per PFP. The only currently defined Signature is "SPDM Device Sec",
* which implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2.
* The EV_EFI_SPDM_FIRMWARE_BLOB event is used to record an extended digest for the firmware of
* an embedded component or an add-in device that supports SPDM GET_MEASUREMENTS functionality.
* an embedded component or an add-in device that supports SPDM "GET_MEASUREMENTS" functionality.
* This event records extended digests of SPDM GET_MEASUREMENT responses that correspond to
* firmware, such as immutable ROM, mutable firmware, firmware version, firmware secure version
* number, etc.

View File

@ -271,4 +271,19 @@ public final class UefiConstants {
* standard UEFI partition table lengh.
*/
public static final int UEFI_PT_LENGTH = 72;
/**
* file status, where file was successfully found on local machine.
*/
public static final String FILESTATUS_FROM_FILESYSTEM = "fileFromFilesystem";
/**
* file status, where file was not found on local machine, so file from code was used.
* For instance, if vendor-table.json is not found in filesystem at location
* /etc/hirs/aca/default-properties/, it will be grabbed from code at
* HIRS_AttestationCA/src/main/resources/.
*/
public static final String FILESTATUS_FROM_CODE = "fileFromCode";
/**
* file status, where file is not accessible (either not found, or no access permission).
*/
public static final String FILESTATUS_NOT_ACCESSIBLE = "fileNotAccessible";
}

View File

@ -3,12 +3,17 @@ package hirs.utils.tpm.eventlog.uefi;
import com.eclipsesource.json.JsonObject;
import hirs.utils.HexUtils;
import hirs.utils.JsonUtils;
import lombok.Getter;
import java.math.BigInteger;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.UUID;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_FROM_CODE;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_FROM_FILESYSTEM;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIBLE;
/**
* Class to process GUID per the UEFI specification
* GUIDs are essentially UUID as defined by RFC-1422, however Microsoft refers to GUIDS.
@ -22,10 +27,25 @@ public class UefiGuid {
* used for conversion to uuid time.
*/
private static final int UUID_EPOCH_DIVISOR = 10000;
/**
* Filesystem path of vendor-table.json
*/
private static final Path JSON_PATH = FileSystems.getDefault().getPath("/etc",
"hirs", "aca", "default-properties", "vendor-table.json");
/**
* Name of vendor-table file in code
*/
private static final String JSON_FILENAME = "vendor-table.json";
/**
* Reference to the vendor-table json object
*/
private JsonObject uefiVendorRef;
/**
* Track status of vendor-table.json
*/
@Getter
private String vendorTableFileStatus = FILESTATUS_NOT_ACCESSIBLE;
/**
* guid byte array.
*/
@ -41,10 +61,7 @@ public class UefiGuid {
* @param guidBytes byte array holding a valid guid.
*/
public UefiGuid(final byte[] guidBytes) {
guid = new byte[UefiConstants.SIZE_16];
System.arraycopy(guidBytes, 0, guid, 0, UefiConstants.SIZE_16);
uuid = processGuid(guidBytes);
uefiVendorRef = JsonUtils.getSpecificJsonObject(JSON_PATH, "VendorTable");
this(guidBytes, JSON_PATH);
}
/**
@ -59,6 +76,17 @@ public class UefiGuid {
uuid = processGuid(guidBytes);
uefiVendorRef = JsonUtils.getSpecificJsonObject(vendorPathString,
"VendorTable");
if(!isVendorTableReferenceHandleEmpty()) {
vendorTableFileStatus = FILESTATUS_FROM_FILESYSTEM;
}
else {
// could not access vendor-table.json from filesystem, so attempt to access from code
uefiVendorRef = JsonUtils.getSpecificJsonObject(JSON_FILENAME, "VendorTable");
if(!isVendorTableReferenceHandleEmpty()) {
vendorTableFileStatus = FILESTATUS_FROM_CODE;
}
}
}
/**
@ -97,6 +125,16 @@ public class UefiGuid {
return UefiConstants.SIZE_16;
}
/**
* Checks whether the handle to the file needed to look up the UUID is valid. If empty,
* this likely means the file was not accessible to due to existence or permissions.
*
* @return true if the reference to the file handle needed to look up the UUID is empty
*/
public boolean isVendorTableReferenceHandleEmpty() {
return uefiVendorRef.isEmpty();
}
/**
* Returns a String that represents a specification name referenced by the
* EFI_CONFIGURATION_TABLE VendorGUID field. For structure of

View File

@ -9,6 +9,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIBLE;
/**
* Class for processing the contents of a Secure Boot DB or DBX contents.
* used for EFIVariables associated with Secure Boot
@ -69,6 +71,11 @@ public class UefiSignatureList {
* Type of signature.
*/
private UefiGuid signatureType = null;
/**
* Track status of vendor-table.json
*/
@Getter
private String vendorTableFileStatus = FILESTATUS_NOT_ACCESSIBLE;
/**
* UefiSignatureList constructor.
@ -84,6 +91,7 @@ public class UefiSignatureList {
byte[] guid = new byte[UefiConstants.SIZE_16];
System.arraycopy(list, 0, guid, 0, UefiConstants.SIZE_16);
signatureType = new UefiGuid(guid);
vendorTableFileStatus = signatureType.getVendorTableFileStatus();
byte[] lSize = new byte[UefiConstants.SIZE_4];
System.arraycopy(list, UefiConstants.OFFSET_16, lSize, 0, UefiConstants.SIZE_4);
@ -114,6 +122,7 @@ public class UefiSignatureList {
byte[] guid = new byte[UefiConstants.SIZE_16];
lists.read(guid);
signatureType = new UefiGuid(guid);
vendorTableFileStatus = signatureType.getVendorTableFileStatus();
// if signatureType is invalid, don't even process any of the data
// however, if signatureTYpe is valid, but some of the data later on is invalid, that will

View File

@ -12,6 +12,9 @@ import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_FROM_FILESYSTEM;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIBLE;
/**
* Class to process a UEFI variable within a TPM Event.
* typedef struct tdUEFI_VARIABLE_DATA{
@ -63,6 +66,15 @@ public class UefiVariable {
*/
private byte[] uefiVariableData = null;
/**
* Track status of vendor-table.json.
* The default here is that each list correctly grabbed the file from file system.
* If any one list has issues, this overall status will change to reflect the
* problematic list's status.
*/
@Getter
private String vendorTableFileStatus = FILESTATUS_FROM_FILESYSTEM;
/**
* EFIVariable constructor.
* The UEFI_VARIABLE_DATA contains a "VariableName" field which is used to determine
@ -146,6 +158,22 @@ public class UefiVariable {
while (certData.available() > 0) {
UefiSignatureList list;
list = new UefiSignatureList(certData);
// first check if any previous list has not been able to access vendor-table.json,
// and if that is the case, the first comparison in the if returns false and
// the if statement is not executed
// [previous event file status = vendorTableFileStatus]
// (ie. keep the file status to reflect that file was not accessible at some point)
// next, check if the new list has any status other than the default 'filesystem',
// and if that is the case, the 2nd comparison in the if returns true and
// the if statement is executed
// [new event file status = list.getVendorTableFileStatus()]
// (ie. if the new file status is not-accessible or from-code, then want to update)
if((vendorTableFileStatus != FILESTATUS_NOT_ACCESSIBLE) &&
(list.getVendorTableFileStatus() != FILESTATUS_FROM_FILESYSTEM)) {
vendorTableFileStatus = list.getVendorTableFileStatus();
}
// efiVariableSigListContents += list.toString();
if(!list.isSignatureTypeValid()) {
invalidSignatureListEncountered = true;
@ -163,6 +191,7 @@ public class UefiVariable {
*/
public String toString() {
StringBuilder efiVariable = new StringBuilder();
efiVariable.append("UEFI Variable Name: " + efiVarName + "\n");
efiVariable.append("UEFI Variable GUID: " + uefiVarGuid.toString() + "\n");
if (efiVarName != "") {

View File

@ -17,7 +17,7 @@ ACA_VERSION_FILE="/opt/hirs/aca/VERSION"
SPRING_PROP_FILE="/etc/hirs/aca/application.properties"
PROP_FILE='../../../HIRS_AttestationCAPortal/src/main/resources/application.properties'
COMP_JSON='../../../HIRS_AttestationCA/src/main/resources/component-class.json'
VENDOR_TABLE='../../../HIRS_AttestationCA/src/main/resources/vendor-table.json'
VENDOR_TABLE='../../../HIRS_Utils/src/main/resources/vendor-table.json'
help () {
echo " Setup script for the HIRS ACA"

View File

@ -8,7 +8,7 @@ param (
$APP_HOME=(Split-Path -parent $PSCommandPath)
$ACA_COMMON_SCRIPT=(Join-Path $APP_HOME 'aca_common.ps1')
$COMP_JSON=(Join-Path $APP_HOME '..' '..' '..' 'HIRS_AttestationCA' 'src' 'main' 'resources' 'component-class.json')
$VENDOR_TABLE=(Join-Path $APP_HOME '..' '..' '..' 'HIRS_AttestationCA' 'src' 'main' 'resources' 'vendor-table.json')
$VENDOR_TABLE=(Join-Path $APP_HOME '..' '..' '..' 'HIRS_Utils' 'src' 'main' 'resources' 'vendor-table.json')
# Load other scripts
. $ACA_COMMON_SCRIPT

View File

@ -16,6 +16,9 @@ import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import hirs.utils.HexUtils;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_FROM_CODE;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIBLE;
/**
* Command-line application for processing TCG Event Logs.
* Input arg: path to *.tcglp file
@ -127,6 +130,19 @@ final class Main {
writeOut("\nEvent Log follows the \"SHA1\" format and has "
+ 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");
}
}
int eventCount = 0;
for (TpmPcrEvent event : evLog.getEventList()) {