Merge pull request #527 from nsacyber/issue-497-remote

[#497] Add support for composite RIMs
This commit is contained in:
chubtub 2023-06-22 19:50:20 -04:00 committed by GitHub
commit 0535c3c1ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 176 additions and 66 deletions

Binary file not shown.

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SoftwareIdentity xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" corpus="false" name="Example.com BIOS" patch="false" supplemental="false" tagId="94f6b457-9ac9-4d35-9b3f-78804173b65as" tagVersion="0" version="01" versionScheme="multipartnumeric" xml:lang="en">
<Entity name="Example Inc" regid="http://Example.com" role="softwareCreator tagCreator"/>
<Link href="https://Example.com/support/ProductA/firmware/installfiles" rel="installationmedia"/>
<Meta xmlns:n8060="http://csrc.nist.gov/ns/swid/2015-extensions/1.0" xmlns:rim="https://trustedcomputinggroup.org/wp-content/uploads/TCG_RIM_Model" n8060:colloquialVersion="Firmware_2019" n8060:edition="12" n8060:product="ProductA" n8060:revision="r2" rim:BindingSpec="PC Client RIM" rim:BindingSpecVersion="1.2" rim:PayloadType="direct" rim:firmwareManufacturerId="00213022" rim:firmwareManufacturerStr="BIOSVendorA" rim:firmwareModel="A0" rim:firmwareVersion="12" rim:pcURIGlobal="https://Example.com/support/ProductA/" rim:pcURILocal="/boot/tcg/manifest/switag/" rim:platformManufacturerId="00201234" rim:platformManufacturerStr="Example.com" rim:platformModel="ProductA" rim:platformVersion="01"/>
<Payload>
<Directory name="rim">
<File xmlns:SHA256="http://www.w3.org/2001/04/xmlenc#sha256" SHA256:hash="4479ca722623f8c47b703996ced3cbd981b06b1ae8a897db70137e0b7c546848" name="TpmLog.bin" size="7549"/>
</Directory>
</Payload>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>Ao7tTmXHCYeFmCJ0R6AY3cdfpyj1PdMq4yC9HJTDanY=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>HNyKHDH8Q+Ii5pjzGJL3JV+4VdMObhE4EV7S7rfvZLeqFgkbmWe1jILv4Km0PXdHN8jJYxU+HT8R&#13;
akV0sab11+oope50lvivfPR3MspkdB0hxTyEq92z6m3MrBbjAtIgfsAnmq68LQ33je8vuL8jXAS9&#13;
xhLBQq8spYXTKpMvbiaipAqD4NOzsUxpk5htPDsEImChaHGKVMlDZlSL5dL4Vh/FvDj6UrUNxp2d&#13;
ltXl+Vov0tlh5dj2g8g2OlJXiMbxr47Qssn6EaUWmcNu+cdrhvWhpYJGc3mZdEWnsV8bvGNrC2tU&#13;
TVIBVsDLOmw5sVPoFrnvWc41sPVDSF0dKLwIYA==</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx&#13;
xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9&#13;
dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q&#13;
otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW&#13;
jDQeHiY0VIoPik/jVVIpjWe6zzeZ2S66Q/LmjQ==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</SoftwareIdentity>

View File

@ -32,9 +32,10 @@
"Directory": {
"supportRIMFormat": "TCG_EventLog_Assertion",
"name": "iotBase",
"File": {
"name": "TpmLog.bin"
}
"File": [
{ "name": "TpmLog.bin" },
{ "name": "generated_swidTag.swidtag" }
]
}
}
}

View File

@ -17,7 +17,7 @@ public class Main {
SwidTagGateway gateway;
SwidTagValidator validator;
CredentialArgumentValidator caValidator;
String rimEventLogFile, trustStoreFile, certificateFile, privateKeyFile;
String rimEventLogFile, trustStoreFile, certificateFile, privateKeyFile, directory;
if (commander.isHelp()) {
jc.usage();
@ -30,6 +30,7 @@ public class Main {
certificateFile = commander.getPublicCertificate();
privateKeyFile = commander.getPrivateKeyFile();
trustStoreFile = commander.getTruststoreFile();
directory = commander.getDirectoryOverride();
boolean defaultKey = commander.isDefaultKey();
if (defaultKey) {
validator.validateSwidTag(verifyFile, "DEFAULT");
@ -37,8 +38,10 @@ public class Main {
caValidator = new CredentialArgumentValidator(trustStoreFile,
certificateFile, privateKeyFile, "", "", true);
if (caValidator.isValid()) {
if (!directory.isEmpty()) {
validator.setDirectoryOverride(directory);
}
validator.setTrustStoreFile(trustStoreFile);
validator.validateSwidTag(verifyFile, caValidator.getFormat());
} else {
System.out.println("Invalid combination of credentials given: "
@ -53,6 +56,7 @@ public class Main {
trustStoreFile = commander.getTruststoreFile();
certificateFile = commander.getPublicCertificate();
privateKeyFile = commander.getPrivateKeyFile();
directory = commander.getDirectoryOverride();
boolean embeddedCert = commander.isEmbedded();
boolean defaultKey = commander.isDefaultKey();
String outputFile = commander.getOutFile();
@ -85,6 +89,9 @@ public class Main {
if (embeddedCert) {
gateway.setEmbeddedCert(true);
}
if (!directory.isEmpty()) {
gateway.setDirectoryOverride(directory);
}
}
gateway.setRimEventLog(rimEventLogFile);
List<String> timestampArguments = commander.getTimestampArguments();

View File

@ -15,6 +15,7 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonException;
import javax.json.JsonObject;
import javax.json.JsonReader;
@ -76,6 +77,7 @@ import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -93,10 +95,11 @@ public class SwidTagGateway {
private String truststoreFile;
private String pemPrivateKeyFile;
private String pemCertificateFile;
private boolean embeddedCert;
private String rimEventLog;
private boolean embeddedCert;
private String timestampFormat;
private String timestampArgument;
private String directoryOverride;
private String errorRequiredFields;
/**
@ -110,10 +113,11 @@ public class SwidTagGateway {
defaultCredentials = true;
truststoreFile = "";
pemCertificateFile = "";
embeddedCert = false;
rimEventLog = "";
embeddedCert = false;
timestampFormat = "";
timestampArgument = "";
directoryOverride = "";
errorRequiredFields = "";
} catch (JAXBException e) {
System.out.println("Error initializing jaxbcontext: " + e.getMessage());
@ -176,11 +180,11 @@ public class SwidTagGateway {
}
/**
* Setter for event log support RIM
* Setter for rim event log file
*
* @param rimEventLog
*/
public void setRimEventLog(final String rimEventLog) {
public void setRimEventLog(String rimEventLog) {
this.rimEventLog = rimEventLog;
}
@ -202,6 +206,15 @@ public class SwidTagGateway {
this.timestampArgument = timestampArgument;
}
/**
* Setter for directory path to search for required files
*
* @param directoryOverride
*/
public void setDirectoryOverride(String directoryOverride) {
this.directoryOverride = directoryOverride;
}
/**
* This method generates a base RIM from the values in a JSON file.
*
@ -237,12 +250,16 @@ public class SwidTagGateway {
configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
.getJsonObject(SwidTagConstants.DIRECTORY));
//File
hirs.swid.xjc.File file = createFile(
configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
.getJsonObject(SwidTagConstants.DIRECTORY)
.getJsonObject(SwidTagConstants.FILE));
//Nest File in Directory in Payload
directory.getDirectoryOrFile().add(file);
JsonArray fileArray = configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
.getJsonObject(SwidTagConstants.DIRECTORY)
.getJsonArray(SwidTagConstants.FILE);
Iterator itr = fileArray.iterator();
while(itr.hasNext()) {
JsonObject arrayItem = (JsonObject) itr.next();
hirs.swid.xjc.File file = createFile(arrayItem);
//Nest File in Directory in Payload
directory.getDirectoryOrFile().add(file);
}
payload.getDirectoryOrFileOrProcess().add(directory);
JAXBElement<ResourceCollection> jaxbPayload =
objectFactory.createSoftwareIdentityPayload(payload);
@ -263,8 +280,12 @@ public class SwidTagGateway {
} catch (FileNotFoundException e) {
System.out.println("File does not exist or cannot be read: " + e.getMessage());
System.exit(1);
} catch (ClassCastException e) {
System.out.println("File object in JSON attributes file must be an array.");
System.exit(1);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
System.exit(1);
}
}
@ -506,9 +527,9 @@ public class SwidTagGateway {
* @param jsonObject the Properties object containing parameters from file
* @return File object created from the properties
*/
private hirs.swid.xjc.File createFile(JsonObject jsonObject) throws Exception {
private hirs.swid.xjc.File createFile(JsonObject jsonObject)
throws Exception {
hirs.swid.xjc.File file = objectFactory.createFile();
file.setName(jsonObject.getString(SwidTagConstants.NAME, ""));
Map<QName, String> attributes = file.getOtherAttributes();
String supportRimFormat = jsonObject.getString(SwidTagConstants.SUPPORT_RIM_FORMAT,
SwidTagConstants.SUPPORT_RIM_FORMAT_MISSING);
@ -524,11 +545,13 @@ public class SwidTagGateway {
jsonObject.getString(SwidTagConstants.SUPPORT_RIM_TYPE, ""));
addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_URI_GLOBAL,
jsonObject.getString(SwidTagConstants.SUPPORT_RIM_URI_GLOBAL, ""));
File rimEventLogFile = new File(rimEventLog);
file.setSize(new BigInteger(Long.toString(rimEventLogFile.length())));
String filepath = directoryOverride + jsonObject.getString(SwidTagConstants.NAME);
File fileToAdd = new File(filepath);
file.setName(filepath);
file.setSize(new BigInteger(Long.toString(fileToAdd.length())));
addNonNullAttribute(attributes, SwidTagConstants._SHA256_HASH,
jsonObject.getString(SwidTagConstants.HASH,
HashSwid.get256Hash(rimEventLog)), true);
HashSwid.get256Hash(filepath)), true);
return file;
}

View File

@ -5,7 +5,6 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.security.auth.x500.X500Principal;
@ -27,9 +26,6 @@ import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
@ -42,9 +38,6 @@ import javax.xml.validation.SchemaFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyException;
@ -65,10 +58,10 @@ import java.util.List;
*/
public class SwidTagValidator {
private Unmarshaller unmarshaller;
private String rimEventLog;
private String certificateFile;
private String trustStoreFile;
private List<X509Certificate> trustStore;
private String directoryOverride;
/**
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
@ -78,15 +71,6 @@ public class SwidTagValidator {
Security.addProvider(new BouncyCastleProvider());
}
/**
* Setter for rimel file path.
*
* @param rimEventLog the rimel file
*/
public void setRimEventLog(String rimEventLog) {
this.rimEventLog = rimEventLog;
}
/**
* Setter for the truststore file path.
*
@ -96,13 +80,21 @@ public class SwidTagValidator {
this.trustStoreFile = trustStoreFile;
}
/**
* Setter for directory override path.
* @param directoryOverride directory path
*/
public void setDirectoryOverride(String directoryOverride) {
this.directoryOverride = directoryOverride;
}
public SwidTagValidator() {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(SwidTagConstants.SCHEMA_PACKAGE);
unmarshaller = jaxbContext.createUnmarshaller();
rimEventLog = "";
certificateFile = "";
trustStoreFile = SwidTagConstants.DEFAULT_KEYSTORE_FILE;
directoryOverride = "";
} catch (JAXBException e) {
System.out.println("Error initializing JAXBContext: " + e.getMessage());
}
@ -127,7 +119,10 @@ public class SwidTagValidator {
si.append("SoftwareIdentity name: " + softwareIdentity.getAttribute("name") + "\n");
si.append("SoftwareIdentity tagId: " + softwareIdentity.getAttribute("tagId") + "\n");
System.out.println(si.toString());
return validateEnvelopedSignature(document, format);
Element directory = (Element) document.getElementsByTagName("Directory").item(0);
if (validateDirectory(directory)) {
return validateEnvelopedSignature(document, format);
}
} else {
System.out.println("Invalid xml for validation, please verify " + path);
}
@ -136,13 +131,6 @@ public class SwidTagValidator {
}
private boolean validateEnvelopedSignature(Document doc, String format) {
Element file = (Element) doc.getElementsByTagName("File").item(0);
try {
validateFile(file);
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
}
boolean swidtagValidity = validateSignedXMLDocument(doc, format);
if (swidtagValidity) {
System.out.println("Signature core validity: true");
@ -181,24 +169,39 @@ public class SwidTagValidator {
return validateSignedXMLDocument(doc, format);
}
/**
* This method iterates over the list of File elements under the directory.
*
* @param directory the Directory element
*/
private boolean validateDirectory(Element directory) {
boolean isValid = true;
NodeList fileNodeList = directory.getChildNodes();
for (int i = 0;i < fileNodeList.getLength();i++) {
Element file = (Element) fileNodeList.item(i);
isValid &= validateFile(file);
}
return isValid;
}
/**
* This method validates a hirs.swid.xjc.File from an indirect payload
*/
private boolean validateFile(Element file) throws Exception {
String filepath;
if (!rimEventLog.isEmpty()) {
filepath = rimEventLog;
} else {
filepath = file.getAttribute(SwidTagConstants.NAME);
}
System.out.println("Support rim found at " + filepath);
if (HashSwid.get256Hash(filepath).equals(
file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":" +
SwidTagConstants._SHA256_HASH.getLocalPart()))) {
System.out.println("Support RIM hash verified!" + System.lineSeparator());
return true;
} else {
System.out.println("Support RIM hash does not match Base RIM!" + System.lineSeparator());
private boolean validateFile(Element file) {
String filepath = directoryOverride + file.getAttribute(SwidTagConstants.NAME);
try {
if (HashSwid.get256Hash(filepath).equals(
file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":" +
SwidTagConstants._SHA256_HASH.getLocalPart()))) {
System.out.println("Support RIM hash verified for " + filepath);
return true;
} else {
System.out.println("Hash of " + filepath + " does not match value in Base RIM");
return false;
}
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
}
}

View File

@ -49,7 +49,7 @@ public class Commander {
@Parameter(names = {"-d", "--default-key"}, order = 9,
description = "Use keystore.jks from the rimtool installation to sign.")
private boolean defaultKey = false;
@Parameter(names = {"-l", "--rimel <path>"}, order = 10, required = true,
@Parameter(names = {"-l", "--rimel <path>"}, order = 10,
description = "The TCG eventlog file to use as a support RIM.")
private String rimEventLog = "";
@Parameter(names = {"--timestamp"}, order = 11, variableArity = true,
@ -57,6 +57,9 @@ public class Commander {
"Currently only RFC3339 and RFC3852 are supported:\n" +
"\tRFC3339 [yyyy-MM-ddThh:mm:ssZ]\n\tRFC3852 <counterSignature.bin>")
private List<String> timestampArguments = new ArrayList<String>(2);
@Parameter(names = {"--directory"}, validateWith = DirectoryArgumentValidator.class,
description = "The directory in which to locate required files.")
private String directoryOverride = "";
public boolean isHelp() {
return help;
@ -110,6 +113,10 @@ public class Commander {
return timestampArguments;
}
public String getDirectoryOverride() {
return directoryOverride;
}
public String printHelpExamples() {
StringBuilder sb = new StringBuilder();
sb.append("Create a base RIM using the values in attributes.json; " +
@ -157,7 +164,8 @@ public class Commander {
+ System.lineSeparator());
sb.append("Embedded certificate: " + this.isEmbedded() + System.lineSeparator());
}
sb.append("Event log support RIM: " + this.getRimEventLog() + System.lineSeparator());
sb.append("Override payload directory with: " + this.getDirectoryOverride()
+ System.lineSeparator());
List<String> timestampArguments = this.getTimestampArguments();
if (timestampArguments.size() > 0) {
sb.append("Timestamp format: " + timestampArguments.get(0));
@ -165,7 +173,7 @@ public class Commander {
sb.append(", " + timestampArguments.get(1));
}
} else {
sb.append("No timestamp included");
sb.append("No timestamp included" + System.lineSeparator());
}
return sb.toString();
}

View File

@ -0,0 +1,26 @@
package hirs.swid.utils;
import com.beust.jcommander.IParameterValidator;
import com.beust.jcommander.ParameterException;
import java.io.File;
/**
* This class validates a directory argument. If the directory is neither valid nor
* read-accessible then an error is thrown.
*/
public class DirectoryArgumentValidator implements IParameterValidator {
public void validate(String name, String value) throws ParameterException {
try {
File directory = new File(value);
if (!directory.isDirectory()) {
throw new ParameterException("Invalid directory given: " + value +
". Please provide a valid directory path.");
}
} catch (SecurityException e) {
throw new ParameterException("Read access denied for " + value +
", please verify permissions.");
}
}
}

View File

@ -45,7 +45,6 @@ public class TestSwidTagGateway {
gateway.setRimEventLog(SUPPORT_RIM_FILE);
gateway.setAttributesFile(ATTRIBUTES_FILE);
validator = new SwidTagValidator();
validator.setRimEventLog(SUPPORT_RIM_FILE);
validator.setTrustStoreFile(CA_CHAIN_FILE);
}

View File

@ -41,12 +41,14 @@
"Directory": {
"name": "rim",
"root": "/boot/tcg/manifest/rim/",
"File": {
"File": [
{
"version":"01",
"name": "Example.com.BIOS.01.rimel",
"size": "7549",
"hash": "4479ca722623f8c47b703996ced3cbd981b06b1ae8a897db70137e0b7c546848"
}
]
}
}
}