diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/rim/BaseReferenceManifest.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/rim/BaseReferenceManifest.java index 2e9b7be5..365fca10 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/rim/BaseReferenceManifest.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/rim/BaseReferenceManifest.java @@ -2,15 +2,9 @@ package hirs.attestationca.persist.entity.userdefined.rim; import com.fasterxml.jackson.annotation.JsonIgnore; import hirs.attestationca.persist.entity.userdefined.ReferenceManifest; -import hirs.attestationca.persist.service.ReferenceManifestServiceImpl; import hirs.utils.SwidResource; -import hirs.utils.xjc.BaseElement; -import hirs.utils.xjc.Directory; -import hirs.utils.xjc.File; -import hirs.utils.xjc.FilesystemItem; +import hirs.utils.swid.SwidTagConstants; import hirs.utils.xjc.Link; -import hirs.utils.xjc.Meta; -import hirs.utils.xjc.ResourceCollection; import hirs.utils.xjc.SoftwareIdentity; import hirs.utils.xjc.SoftwareMeta; import jakarta.persistence.Column; @@ -25,9 +19,21 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.log4j.Log4j2; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -170,8 +176,6 @@ public class BaseReferenceManifest extends ReferenceManifest { } break; case "Payload": - parseResource((ResourceCollection) element.getValue()); - break; case "Signature": // left blank for a followup issue enhancement default: @@ -259,35 +263,67 @@ public class BaseReferenceManifest extends ReferenceManifest { } /** - * Helper method that is used to parse a specific element of the SwidTag - * based on an already established and stored byte array. + * This method validates the .swidtag file at the given filepath against the + * schema. A successful validation results in the output of the tag's name + * and tagId attributes, otherwise a generic error message is printed. * - * @param elementName string of an xml tag in the file. - * @return the object value of the element, if it exists */ - private BaseElement getBaseElementFromBytes(final String elementName) { - BaseElement baseElement = null; + private Element getDirectoryTag() { + return getDirectoryTag(new ByteArrayInputStream(getRimBytes())); + } - if (getRimBytes() != null && elementName != null) { - try { - SoftwareIdentity si = validateSwidTag(new ByteArrayInputStream(getRimBytes())); - JAXBElement element; - for (Object object : si.getEntityOrEvidenceOrLink()) { - if (object instanceof JAXBElement) { - element = (JAXBElement) object; - if (element.getName().getLocalPart().equals(elementName)) { - // found the element - baseElement = (BaseElement) element.getValue(); - } - } - } + /** + * This method validates the .swidtag file at the given filepath against the + * schema. A successful validation results in the output of the tag's name + * and tagId attributes, otherwise a generic error message is printed. + * + * @param byteArrayInputStream the location of the file to be validated + */ + private Element getDirectoryTag(final ByteArrayInputStream byteArrayInputStream) { + Document document = unmarshallSwidTag(byteArrayInputStream); + Element softwareIdentity = + (Element) document.getElementsByTagName("SoftwareIdentity").item(0); + if (softwareIdentity != null) { + Element directory = (Element) document.getElementsByTagName("Directory").item(0); - } catch (IOException ioEx) { - log.error("Failed to parse Swid Tag bytes.", ioEx); - } + return directory; + } else { + log.error("Invalid xml for validation, please verify "); } - return baseElement; + return null; + } + + /** + * This method iterates over the list of File elements under the directory. * + */ + public List getFileResources() { + return getFileResources(getRimBytes()); + } + + /** + * This method iterates over the list of File elements under the directory. + * + * @param rimBytes the bytes to find the files + * + */ + public List getFileResources(final byte[] rimBytes) { + Element directoryTag = getDirectoryTag(new ByteArrayInputStream(rimBytes)); + List validHashes = new ArrayList<>(); + NodeList fileNodeList = directoryTag.getChildNodes(); + Element file = null; + SwidResource swidResource = null; + for (int i = 0; i < fileNodeList.getLength(); i++) { + file = (Element) fileNodeList.item(i); + swidResource = new SwidResource(); + swidResource.setName(file.getAttribute(SwidTagConstants.NAME)); + swidResource.setSize(file.getAttribute(SwidTagConstants.SIZE)); + swidResource.setHashValue(file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":" + + SwidTagConstants._SHA256_HASH.getLocalPart())); + validHashes.add(swidResource); + } + + return validHashes; } /** @@ -301,13 +337,15 @@ public class BaseReferenceManifest extends ReferenceManifest { private JAXBElement unmarshallSwidTag(final InputStream stream) throws IOException { JAXBElement jaxbe = null; Schema schema; + Unmarshaller unmarshaller = null; try { - schema = ReferenceManifestServiceImpl.getSchemaObject(); + SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE); + schema = schemaFactory.newSchema(new StreamSource(stream)); if (jaxbContext == null) { jaxbContext = JAXBContext.newInstance(SCHEMA_PACKAGE); } - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.setSchema(schema); jaxbe = (JAXBElement) unmarshaller.unmarshal(stream); } catch (UnmarshalException umEx) { @@ -316,6 +354,8 @@ public class BaseReferenceManifest extends ReferenceManifest { for (StackTraceElement ste : umEx.getStackTrace()) { log.error(ste.toString()); } + } catch (SAXException e) { + System.out.println("Error setting schema for validation!"); } catch (IllegalArgumentException iaEx) { log.error("Input file empty."); } catch (JAXBException jaxEx) { @@ -332,51 +372,79 @@ public class BaseReferenceManifest extends ReferenceManifest { } /** - * Default method for parsing the payload element. + * This method unmarshalls the swidtag found at [path] into a Document object + * and validates it according to the schema. * - * @return a collection of payload objects. + * @param byteArrayInputStream to the input swidtag + * @return the SoftwareIdentity element at the root of the swidtag + * @throws IOException if the swidtag cannot be unmarshalled or validated */ - public final List parseResource() { - return parseResource((ResourceCollection) this.getBaseElementFromBytes("Payload")); + private Document unmarshallSwidTag(final ByteArrayInputStream byteArrayInputStream) { + InputStream is = null; + Document document = null; + Unmarshaller unmarshaller = null; + try { + document = removeXMLWhitespace(byteArrayInputStream); + SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE); + is = getClass().getClassLoader().getResourceAsStream(SwidTagConstants.SCHEMA_URL); + Schema schema = schemaFactory.newSchema(new StreamSource(is)); + if (jaxbContext == null) { + jaxbContext = JAXBContext.newInstance(SCHEMA_PACKAGE); + } + unmarshaller = jaxbContext.createUnmarshaller(); + unmarshaller.setSchema(schema); + unmarshaller.unmarshal(document); + } catch (IOException e) { + log.error(e.getMessage()); + } catch (SAXException e) { + log.error("Error setting schema for validation!"); + } catch (UnmarshalException e) { + log.error("Error validating swidtag file!"); + } catch (IllegalArgumentException e) { + log.error("Input file empty."); + } catch (JAXBException e) { + e.printStackTrace(); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + System.out.println("Error closing input stream"); + } + } + } + + return document; } /** - * This method parses the payload method of a {@link ResourceCollection}. + * This method strips all whitespace from an xml file, including indents and spaces + * added for human-readability. * - * @param rc Resource Collection object. - * @return a collection of payload objects. + * @param byteArrayInputStream to the xml file + * @return Document object without whitespace */ - public final List parseResource(final ResourceCollection rc) { - List resources = new ArrayList<>(); - - log.error("Parsing stuff"); - try { - if (rc != null) { - for (Meta meta : rc.getDirectoryOrFileOrProcess()) { - if (meta instanceof Directory) { - Directory directory = (Directory) meta; - for (FilesystemItem fsi : directory.getDirectoryOrFile()) { - if (fsi != null) { - resources.add(new SwidResource( - (File) fsi, null)); - } else { - log.error("fsi is negative"); - } - } - } else if (meta instanceof File) { - resources.add(new SwidResource((File) meta, null)); - } - } - } else { - log.error("ResourceCollection is negative"); + private Document removeXMLWhitespace(final ByteArrayInputStream byteArrayInputStream) throws IOException { + TransformerFactory tf = TransformerFactory.newInstance(); + Source source = new StreamSource( + getClass().getClassLoader().getResourceAsStream("identity_transform.xslt")); + Document document = null; + if (byteArrayInputStream.available() > 0) { + try { + Transformer transformer = tf.newTransformer(source); + DOMResult result = new DOMResult(); + transformer.transform(new StreamSource(byteArrayInputStream), result); + document = (Document) result.getNode(); + } catch (TransformerConfigurationException tcEx) { + log.error("Error configuring transformer!"); + } catch (TransformerException tEx) { + log.error("Error transforming input!"); } - } catch (ClassCastException ccEx) { - log.error(ccEx); - log.error("At this time, the code does not support the " - + "particular formatting of this SwidTag's Payload."); + } else { + throw new IOException("Input file is empty!"); } - return resources; + return document; } @Override diff --git a/HIRS_AttestationCA/src/main/resources/identity_transform.xslt b/HIRS_AttestationCA/src/main/resources/identity_transform.xslt new file mode 100644 index 00000000..e5b58225 --- /dev/null +++ b/HIRS_AttestationCA/src/main/resources/identity_transform.xslt @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java index fb961f70..901c53c0 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java @@ -245,7 +245,7 @@ public class ReferenceManifestDetailsPageController extends PageController resources = baseRim.parseResource(); + List resources = baseRim.getFileResources(); TCGEventLog logProcessor = null; List subManifests; SupportReferenceManifest support = null; diff --git a/HIRS_Utils/src/main/java/hirs/utils/BouncyCastleUtils.java b/HIRS_Utils/src/main/java/hirs/utils/BouncyCastleUtils.java index a5ba12aa..d04cd993 100644 --- a/HIRS_Utils/src/main/java/hirs/utils/BouncyCastleUtils.java +++ b/HIRS_Utils/src/main/java/hirs/utils/BouncyCastleUtils.java @@ -27,7 +27,8 @@ public final class BouncyCastleUtils { */ public static boolean x500NameCompare(final String nameValue1, final String nameValue2) { if (nameValue1 == null || nameValue2 == null) { - throw new IllegalArgumentException("Provided DN string is null."); + log.error("Provided DN string is null."); + return true; } boolean result = false; diff --git a/HIRS_Utils/src/main/java/hirs/utils/SwidResource.java b/HIRS_Utils/src/main/java/hirs/utils/SwidResource.java index ee9f947e..342dffa7 100644 --- a/HIRS_Utils/src/main/java/hirs/utils/SwidResource.java +++ b/HIRS_Utils/src/main/java/hirs/utils/SwidResource.java @@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; import hirs.utils.digest.DigestAlgorithm; import hirs.utils.xjc.File; import lombok.Getter; +import lombok.Setter; import lombok.ToString; import javax.xml.namespace.QName; @@ -18,9 +19,10 @@ import java.util.Map; public class SwidResource { @Getter - private String name, size; + @Setter + private String name, size, hashValue; @Getter - private String rimFormat, rimType, rimUriGlobal, hashValue; + private String rimFormat, rimType, rimUriGlobal; // private TpmWhiteListBaseline tpmWhiteList; private DigestAlgorithm digest = DigestAlgorithm.SHA1; @Getter diff --git a/HIRS_Utils/src/main/java/hirs/utils/swid/SwidTagConstants.java b/HIRS_Utils/src/main/java/hirs/utils/swid/SwidTagConstants.java new file mode 100644 index 00000000..dd6b2916 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/swid/SwidTagConstants.java @@ -0,0 +1,137 @@ +package hirs.utils.swid; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; + + +/** + * This class contains the String constants that are referenced by the gateway + * class. It is expected that member properties of this class will expand as + * more functionality is added to SwidTagGateway. + */ +public class SwidTagConstants { + + public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks";//"/opt/hirs/rimtool/keystore.jks"; + public static final String DEFAULT_KEYSTORE_PASSWORD = "password"; + public static final String DEFAULT_PRIVATE_KEY_ALIAS = "1"; + public static final String DEFAULT_ATTRIBUTES_FILE = "/opt/hirs/rimtool/rim_fields.json"; + public static final String DEFAULT_ENGLISH = "en"; + + public static final String SIGNATURE_ALGORITHM_RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; + + public static final String SCHEMA_PACKAGE = "hirs.swid.xjc"; + public static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI; + public static final String SCHEMA_URL = "swid_schema.xsd"; + + public static final String SOFTWARE_IDENTITY = "SoftwareIdentity"; + public static final String ENTITY = "Entity"; + public static final String LINK = "Link"; + public static final String META = "Meta"; + public static final String PAYLOAD = "Payload"; + public static final String DIRECTORY = "Directory"; + public static final String FILE = "File"; + public static final String NAME = "name"; + public static final String VERSION = "version"; + public static final String VERSION_SCHEME = "versionScheme"; + public static final String TAGID = "tagId"; + public static final String TAGVERSION = "tagVersion"; + public static final String CORPUS = "corpus"; + public static final String PATCH = "patch"; + public static final String SUPPLEMENTAL = "supplemental"; + public static final String REGID = "regid"; + public static final String ROLE = "role"; + public static final String THUMBPRINT = "thumbprint"; + public static final String HREF = "href"; + public static final String REL = "rel"; + public static final String COLLOQUIAL_VERSION = "colloquialVersion"; + public static final String EDITION = "edition"; + public static final String PRODUCT = "product"; + public static final String REVISION = "revision"; + public static final String PAYLOAD_TYPE = "PayloadType"; + public static final String HYBRID = "hybrid"; + public static final String PLATFORM_MANUFACTURER_STR = "platformManufacturerStr"; + public static final String PLATFORM_MANUFACTURER_ID = "platformManufacturerId"; + public static final String PLATFORM_MODEL = "platformModel"; + public static final String PLATFORM_VERSION = "platformVersion"; + public static final String FIRMWARE_MANUFACTURER_STR = "firmwareManufacturerStr"; + public static final String FIRMWARE_MANUFACTURER_ID = "firmwareManufacturerId"; + public static final String FIRMWARE_MODEL = "firmwareModel"; + public static final String FIRMWARE_VERSION = "firmwareVersion"; + public static final String BINDING_SPEC = "bindingSpec"; + public static final String BINDING_SPEC_VERSION = "bindingSpecVersion"; + public static final String PC_URI_LOCAL = "pcURIlocal"; + public static final String PC_URI_GLOBAL = "pcURIGlobal"; + public static final String RIM_LINK_HASH = "rimLinkHash"; + public static final String SIZE = "size"; + public static final String HASH = "hash"; + public static final String SUPPORT_RIM_TYPE = "supportRIMType"; + public static final String SUPPORT_RIM_FORMAT = "supportRIMFormat"; + public static final String TCG_EVENTLOG_ASSERTION = "TCG_EventLog_Assertion"; + public static final String TPM_PCR_ASSERTION = "TPM_PCR_Assertion"; + public static final String SUPPORT_RIM_FORMAT_MISSING = "supportRIMFormat missing"; + public static final String SUPPORT_RIM_URI_GLOBAL = "supportRIMURIGlobal"; + public static final String DATETIME = "dateTime"; + + public static final String NIST_NS = "http://csrc.nist.gov/ns/swid/2015-extensions/1.0"; + public static final String TCG_NS = "https://trustedcomputinggroup.org/wp-content/uploads/TCG_RIM_Model"; + public static final String RFC3852_NS = "https://www.ietf.org/rfc/rfc3852.txt"; + public static final String RFC3339_NS = "https://www.ietf.org/rfc/rfc3339.txt"; + + public static final String N8060_PFX = "n8060"; + public static final String RIM_PFX = "rim"; + public static final String RFC3852_PFX = "rcf3852"; + public static final String RFC3339_PFX = "rcf3339"; + + public static final QName _SHA256_HASH = new QName( + "http://www.w3.org/2001/04/xmlenc#sha256", HASH, "SHA256"); + public static final QName _COLLOQUIAL_VERSION = new QName( + NIST_NS, COLLOQUIAL_VERSION, N8060_PFX); + public static final QName _EDITION = new QName( + NIST_NS, EDITION, N8060_PFX); + public static final QName _PRODUCT = new QName( + NIST_NS, PRODUCT, N8060_PFX); + public static final QName _REVISION = new QName( + NIST_NS, REVISION, N8060_PFX); + public static final QName _PAYLOAD_TYPE = new QName( + TCG_NS, PAYLOAD_TYPE, RIM_PFX); + public static final QName _PLATFORM_MANUFACTURER_STR = new QName( + TCG_NS, PLATFORM_MANUFACTURER_STR, RIM_PFX); + public static final QName _PLATFORM_MANUFACTURER_ID = new QName( + TCG_NS, PLATFORM_MANUFACTURER_ID, RIM_PFX); + public static final QName _PLATFORM_MODEL = new QName( + TCG_NS, PLATFORM_MODEL, RIM_PFX); + public static final QName _PLATFORM_VERSION = new QName( + TCG_NS, PLATFORM_VERSION, RIM_PFX); + public static final QName _FIRMWARE_MANUFACTURER_STR = new QName( + TCG_NS, FIRMWARE_MANUFACTURER_STR, RIM_PFX); + public static final QName _FIRMWARE_MANUFACTURER_ID = new QName( + TCG_NS, FIRMWARE_MANUFACTURER_ID, RIM_PFX); + public static final QName _FIRMWARE_MODEL = new QName( + TCG_NS, FIRMWARE_MODEL, RIM_PFX); + public static final QName _FIRMWARE_VERSION = new QName( + TCG_NS, FIRMWARE_VERSION, RIM_PFX); + public static final QName _BINDING_SPEC = new QName( + TCG_NS, BINDING_SPEC, RIM_PFX); + public static final QName _BINDING_SPEC_VERSION = new QName( + TCG_NS, BINDING_SPEC_VERSION, RIM_PFX); + public static final QName _PC_URI_LOCAL = new QName( + TCG_NS, PC_URI_LOCAL, RIM_PFX); + public static final QName _PC_URI_GLOBAL = new QName( + TCG_NS, PC_URI_GLOBAL, RIM_PFX); + public static final QName _RIM_LINK_HASH = new QName( + TCG_NS, RIM_LINK_HASH, RIM_PFX); + public static final QName _SUPPORT_RIM_TYPE = new QName( + TCG_NS, SUPPORT_RIM_TYPE, RIM_PFX); + public static final QName _SUPPORT_RIM_FORMAT = new QName( + TCG_NS, SUPPORT_RIM_FORMAT, RIM_PFX); + public static final QName _SUPPORT_RIM_URI_GLOBAL = new QName( + TCG_NS, SUPPORT_RIM_URI_GLOBAL, RIM_PFX); + public static final QName _N8060_ENVVARPREFIX = new QName( + NIST_NS, "envVarPrefix", N8060_PFX); + public static final QName _N8060_ENVVARSUFFIX = new QName( + NIST_NS, "envVarSuffix", N8060_PFX); + public static final QName _N8060_PATHSEPARATOR = new QName( + NIST_NS, "pathSeparator", N8060_PFX); + + public static final String CA_ISSUERS = "1.3.6.1.5.5.7.48.2"; +}