From cfbd8f2e389f6abee03acb55a38d518b54e31295 Mon Sep 17 00:00:00 2001
From: chubtub <43381989+chubtub@users.noreply.github.com>
Date: Thu, 11 Apr 2024 09:14:09 -0400
Subject: [PATCH] Modify BaseReferenceManifest to handle namespace prefixes in
 the swidtag XML. Modify the rimtool and ReferenceManifestValidator to
 properly prefix Directory and File under Payload and handle them for
 validation.

---
 .../rim/BaseReferenceManifest.java            | 15 ++-
 .../utils/rim/ReferenceManifestValidator.java |  3 +-
 .../hirs/utils/swid/SwidTagConstants.java     |  1 +
 .../java/hirs/utils/xjc/ObjectFactory.java    | 20 ++++
 .../main/java/hirs/swid/SwidTagConstants.java |  1 +
 .../main/java/hirs/swid/SwidTagGateway.java   | 95 +++++++++++++------
 6 files changed, 98 insertions(+), 37 deletions(-)

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 067e07a5..c5da6001 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
@@ -116,10 +116,14 @@ public class BaseReferenceManifest extends ReferenceManifest {
 
         // begin parsing valid swid tag
         if (document != null) {
-            softwareIdentity = (Element) document.getElementsByTagName(SwidTagConstants.SOFTWARE_IDENTITY).item(0);
-            entity = (Element) document.getElementsByTagName(SwidTagConstants.ENTITY).item(0);
-            link = (Element) document.getElementsByTagName(SwidTagConstants.LINK).item(0);
-            meta = (Element) document.getElementsByTagName(SwidTagConstants.META).item(0);
+            softwareIdentity = (Element) document.getElementsByTagNameNS(
+                    SwidTagConstants.SWIDTAG_NAMESPACE, SwidTagConstants.SOFTWARE_IDENTITY).item(0);
+            entity = (Element) document.getElementsByTagNameNS(
+                    SwidTagConstants.SWIDTAG_NAMESPACE, SwidTagConstants.ENTITY).item(0);
+            link = (Element) document.getElementsByTagNameNS(
+                    SwidTagConstants.SWIDTAG_NAMESPACE, SwidTagConstants.LINK).item(0);
+            meta = (Element) document.getElementsByTagNameNS(
+                    SwidTagConstants.SWIDTAG_NAMESPACE, SwidTagConstants.META).item(0);
             setTagId(softwareIdentity.getAttribute(SwidTagConstants.TAGID));
             this.swidName = softwareIdentity.getAttribute(SwidTagConstants.NAME);
             this.swidCorpus = Boolean.parseBoolean(softwareIdentity.getAttribute(SwidTagConstants.CORPUS)) ? 1 : 0;
@@ -217,7 +221,8 @@ public class BaseReferenceManifest extends ReferenceManifest {
     private Element getDirectoryTag(final ByteArrayInputStream byteArrayInputStream) {
         Document document = unmarshallSwidTag(byteArrayInputStream);
         Element softwareIdentity =
-                (Element) document.getElementsByTagName("SoftwareIdentity").item(0);
+                (Element) document.getElementsByTagNameNS(
+                        SwidTagConstants.SWIDTAG_NAMESPACE,"SoftwareIdentity").item(0);
         if (softwareIdentity != null) {
             Element directory = (Element) document.getElementsByTagName("Directory").item(0);
 
diff --git a/HIRS_Utils/src/main/java/hirs/utils/rim/ReferenceManifestValidator.java b/HIRS_Utils/src/main/java/hirs/utils/rim/ReferenceManifestValidator.java
index ba24450a..a16126a4 100644
--- a/HIRS_Utils/src/main/java/hirs/utils/rim/ReferenceManifestValidator.java
+++ b/HIRS_Utils/src/main/java/hirs/utils/rim/ReferenceManifestValidator.java
@@ -261,7 +261,8 @@ public class ReferenceManifestValidator {
      * @return true if both the file element and signature are valid, false otherwise
      */
     public boolean validateRim(String signingCertPath) {
-        Element fileElement = (Element) rim.getElementsByTagName("File").item(0);
+        Element fileElement = (Element) rim.getElementsByTagNameNS(
+                SwidTagConstants.SWIDTAG_NAMESPACE, "File").item(0);
         X509Certificate signingCert = parseCertificatesFromPem(signingCertPath).get(0);
         if (signingCert == null) {
             return failWithError("Unable to parse the signing cert from " + signingCertPath);
diff --git a/HIRS_Utils/src/main/java/hirs/utils/swid/SwidTagConstants.java b/HIRS_Utils/src/main/java/hirs/utils/swid/SwidTagConstants.java
index 0f6ebdd1..a74e2e49 100644
--- a/HIRS_Utils/src/main/java/hirs/utils/swid/SwidTagConstants.java
+++ b/HIRS_Utils/src/main/java/hirs/utils/swid/SwidTagConstants.java
@@ -22,6 +22,7 @@ public class SwidTagConstants {
     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 SWIDTAG_NAMESPACE = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
 
     public static final String SOFTWARE_IDENTITY = "SoftwareIdentity";
     public static final String ENTITY = "Entity";
diff --git a/HIRS_Utils/src/main/java/hirs/utils/xjc/ObjectFactory.java b/HIRS_Utils/src/main/java/hirs/utils/xjc/ObjectFactory.java
index 598d2f0b..b2a8d0d9 100644
--- a/HIRS_Utils/src/main/java/hirs/utils/xjc/ObjectFactory.java
+++ b/HIRS_Utils/src/main/java/hirs/utils/xjc/ObjectFactory.java
@@ -66,6 +66,8 @@ public class ObjectFactory {
     private final static QName _SoftwareIdentityLink_QNAME = new QName("http://standards.iso.org/iso/19770/-2/2015/schema.xsd", "Link");
     private final static QName _SoftwareIdentityEvidence_QNAME = new QName("http://standards.iso.org/iso/19770/-2/2015/schema.xsd", "Evidence");
     private final static QName _SoftwareIdentityPayload_QNAME = new QName("http://standards.iso.org/iso/19770/-2/2015/schema.xsd", "Payload");
+    private final static QName _PayloadDirectory_QNAME = new QName("http://standards.iso.org/iso/19770/-2/2015/schema.xsd", "Directory");
+    private final static QName _DirectoryFile_QNAME = new QName("http://standards.iso.org/iso/19770/-2/2015/schema.xsd", "File");
     private final static QName _SoftwareIdentityEntity_QNAME = new QName("http://standards.iso.org/iso/19770/-2/2015/schema.xsd", "Entity");
     private final static QName _SoftwareIdentityMeta_QNAME = new QName("http://standards.iso.org/iso/19770/-2/2015/schema.xsd", "Meta");
     private final static QName _SignatureMethodTypeHMACOutputLength_QNAME = new QName("http://www.w3.org/2000/09/xmldsig#", "HMACOutputLength");
@@ -666,6 +668,24 @@ public class ObjectFactory {
         return new JAXBElement<ResourceCollection>(_SoftwareIdentityPayload_QNAME, ResourceCollection.class, SoftwareIdentity.class, value);
     }
 
+    /**
+     * Create an instance of {@link JAXBElement }{@code <}{@link FilesystemItem }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd", name = "Directory", scope = ResourceCollection.class)
+    public JAXBElement<FilesystemItem> createPayloadDirectory(FilesystemItem value) {
+        return new JAXBElement<FilesystemItem>(_PayloadDirectory_QNAME, FilesystemItem.class, ResourceCollection.class, value);
+    }
+
+    /**
+     * Create an instance of {@link JAXBElement }{@code <}{@link FilesystemItem }{@code >}}
+     *
+     */
+    @XmlElementDecl(namespace = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd", name = "File", scope = ResourceCollection.class)
+    public JAXBElement<FilesystemItem> createDirectoryFile(FilesystemItem value) {
+        return new JAXBElement<FilesystemItem>(_DirectoryFile_QNAME, FilesystemItem.class, ResourceCollection.class, value);
+    }
+
     /**
      * Create an instance of {@link JAXBElement }{@code <}{@link Entity }{@code >}}
      * 
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagConstants.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagConstants.java
index 480320ff..b7e5ff94 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagConstants.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagConstants.java
@@ -28,6 +28,7 @@ public class SwidTagConstants {
     public static final String SCHEMA_PACKAGE = "hirs.utils.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 SWIDTAG_NAMESPACE = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
 
     public static final String SOFTWARE_IDENTITY = "SoftwareIdentity";
     public static final String ENTITY = "Entity";
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagGateway.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagGateway.java
index aa9b23d2..43e4d7f8 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagGateway.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagGateway.java
@@ -3,22 +3,24 @@ package hirs.swid;
 import hirs.swid.utils.HashSwid;
 import hirs.utils.xjc.Directory;
 import hirs.utils.xjc.Entity;
+import hirs.utils.xjc.FilesystemItem;
 import hirs.utils.xjc.Link;
 import hirs.utils.xjc.ObjectFactory;
 import hirs.utils.xjc.ResourceCollection;
 import hirs.utils.xjc.SoftwareIdentity;
 import hirs.utils.xjc.SoftwareMeta;
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBElement;
+import jakarta.xml.bind.JAXBException;
+import jakarta.xml.bind.Marshaller;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 
 import javax.json.Json;
 import javax.json.JsonException;
 import javax.json.JsonObject;
 import javax.json.JsonReader;
-import jakarta.xml.bind.JAXBContext;
-import jakarta.xml.bind.JAXBElement;
-import jakarta.xml.bind.JAXBException;
-import jakarta.xml.bind.Marshaller;
 import javax.xml.crypto.MarshalException;
 import javax.xml.crypto.XMLStructure;
 import javax.xml.crypto.dom.DOMStructure;
@@ -41,6 +43,7 @@ import javax.xml.crypto.dsig.keyinfo.X509Data;
 import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
 import javax.xml.crypto.dsig.spec.TransformParameterSpec;
 import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.OutputKeys;
@@ -91,6 +94,8 @@ public class SwidTagGateway {
     private String timestampFormat;
     private String timestampArgument;
     private String errorRequiredFields;
+    private DocumentBuilderFactory dbf;
+    private DocumentBuilder builder;
 
     /**
      * Default constructor initializes jaxbcontext, marshaller, and unmarshaller
@@ -107,8 +112,15 @@ public class SwidTagGateway {
             timestampFormat = "";
             timestampArgument = "";
             errorRequiredFields = "";
+            dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+            builder = dbf.newDocumentBuilder();
         } catch (JAXBException e) {
             System.out.println("Error initializing jaxbcontext: " + e.getMessage());
+        } catch (ParserConfigurationException e) {
+            System.out.println("Error instantiating Document object for parsing swidtag: "
+                    + e.getMessage());
+            System.exit(1);
         }
     }
 
@@ -198,49 +210,62 @@ public class SwidTagGateway {
      * @param filename
      */
     public void generateSwidTag(final String filename) {
-        SoftwareIdentity swidTag = null;
+        Document swidtag = builder.newDocument();
+        SoftwareIdentity softwareIdentity = null;
         try {
             InputStream is = new FileInputStream(attributesFile);
             JsonReader reader = Json.createReader(is);
             JsonObject configProperties = reader.readObject();
             reader.close();
             //SoftwareIdentity
-            swidTag = createSwidTag(
+            softwareIdentity = createSwidTag(
                     configProperties.getJsonObject(SwidTagConstants.SOFTWARE_IDENTITY));
             //Entity
             JAXBElement<Entity> entity = objectFactory.createSoftwareIdentityEntity(
                     createEntity(configProperties.getJsonObject(SwidTagConstants.ENTITY)));
-            swidTag.getEntityOrEvidenceOrLink().add(entity);
+            softwareIdentity.getEntityOrEvidenceOrLink().add(entity);
             //Link
             JAXBElement<Link> link = objectFactory.createSoftwareIdentityLink(
                     createLink(configProperties.getJsonObject(SwidTagConstants.LINK)));
-            swidTag.getEntityOrEvidenceOrLink().add(link);
+            softwareIdentity.getEntityOrEvidenceOrLink().add(link);
             //Meta
             JAXBElement<SoftwareMeta> meta = objectFactory.createSoftwareIdentityMeta(
                     createSoftwareMeta(configProperties.getJsonObject(SwidTagConstants.META)));
-            swidTag.getEntityOrEvidenceOrLink().add(meta);
-            //Payload
-            ResourceCollection payload = createPayload(
-                    configProperties.getJsonObject(SwidTagConstants.PAYLOAD));
-            //Directory
-            Directory directory = createDirectory(
-                    configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
-                            .getJsonObject(SwidTagConstants.DIRECTORY));
+            softwareIdentity.getEntityOrEvidenceOrLink().add(meta);
+
+            swidtag = convertToDocument(objectFactory.createSoftwareIdentity(softwareIdentity));
+            Element rootElement = swidtag.getDocumentElement();
+
             //File
             hirs.utils.xjc.File file = createFile(
                     configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
                             .getJsonObject(SwidTagConstants.DIRECTORY)
                             .getJsonObject(SwidTagConstants.FILE));
-            //Nest File in Directory in Payload
-            directory.getDirectoryOrFile().add(file);
-            payload.getDirectoryOrFileOrProcess().add(directory);
+            JAXBElement<FilesystemItem> jaxbFile = objectFactory.createDirectoryFile(file);
+            Document fileDoc = convertToDocument(jaxbFile);
+            //Directory
+            Directory directory = createDirectory(
+                    configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
+                            .getJsonObject(SwidTagConstants.DIRECTORY));
+            JAXBElement<FilesystemItem> jaxbDirectory = objectFactory.createPayloadDirectory(directory);
+            Document dirDoc = convertToDocument(jaxbDirectory);
+            Node fileNode = dirDoc.importNode(fileDoc.getDocumentElement(), true);
+            dirDoc.getDocumentElement().appendChild(fileNode);
+            //Payload
+            ResourceCollection payload = createPayload(
+                    configProperties.getJsonObject(SwidTagConstants.PAYLOAD));
             JAXBElement<ResourceCollection> jaxbPayload =
                     objectFactory.createSoftwareIdentityPayload(payload);
-            swidTag.getEntityOrEvidenceOrLink().add(jaxbPayload);
+            Document payloadDoc = convertToDocument(jaxbPayload);
+            Node dirNode = payloadDoc.importNode(dirDoc.getDocumentElement(), true);
+            payloadDoc.getDocumentElement().appendChild(dirNode);
+
+            Node payloadNode = swidtag.importNode(payloadDoc.getDocumentElement(), true);
+            rootElement.appendChild(payloadNode);
+
             //Signature
             if (errorRequiredFields.isEmpty()) {
-                Document signedSoftwareIdentity = signXMLDocument(
-                        objectFactory.createSoftwareIdentity(swidTag));
+                Document signedSoftwareIdentity = signXMLDocument(swidtag);
                 writeSwidTagFile(signedSoftwareIdentity, filename);
             } else {
                 System.out.println("The following fields cannot be empty or null: "
@@ -545,23 +570,31 @@ public class SwidTagGateway {
     }
 
     /**
-     * This method signs a SoftwareIdentity with an xmldsig in compatibility mode.
-     * Current assumptions: digest method SHA256, signature method SHA256, enveloped signature
+     * This method converts a JAXBElement object generated from the hirs.utils.xjc package into
+     * a Document object.
+     *
+     * @param element to convert
+     * @return a Document object
      */
-    private Document signXMLDocument(JAXBElement<SoftwareIdentity> swidTag) {
+    private Document convertToDocument(JAXBElement element) {
         Document doc = null;
         try {
-            doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
-            marshaller.marshal(swidTag, doc);
-        } catch (ParserConfigurationException e) {
-            System.out.println("Error instantiating Document object for parsing swidtag: "
-                    + e.getMessage());
-            System.exit(1);
+            doc = builder.newDocument();
+            marshaller.marshal(element, doc);
         } catch (JAXBException e) {
             System.out.println("Error while marshaling swidtag: " + e.getMessage());
             e.printStackTrace();
             System.exit(1);
         }
+
+        return doc;
+    }
+
+    /**
+     * This method signs a SoftwareIdentity with an xmldsig in compatibility mode.
+     * Current assumptions: digest method SHA256, signature method SHA256, enveloped signature
+     */
+    private Document signXMLDocument(Document doc) {
         XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
         List xmlObjectList = null;
         String signatureId = null;