From 6acfb13ce8aa0f5dcf744e4ba543363021718eaf Mon Sep 17 00:00:00 2001
From: chubtub <43381989+chubtub@users.noreply.github.com>
Date: Thu, 1 Jul 2021 10:16:27 -0400
Subject: [PATCH 1/5] Add cert path validation to SwidTagValidator class.
 Modify CredentialParser class to support changes.

---
 .../main/java/hirs/swid/CredentialParser.java |  49 +++++--
 .../src/main/java/hirs/swid/Main.java         |   1 -
 .../main/java/hirs/swid/SwidTagValidator.java | 138 +++++++++++++++++-
 3 files changed, 169 insertions(+), 19 deletions(-)

diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
index 9f24ace0..707e611b 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
@@ -19,6 +19,7 @@ import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.List;
 
 /**
  * This class parses private key, public key, and certificate for use in their respective java.security objects.
@@ -31,6 +32,8 @@ public class CredentialParser {
     private static final String PKCS1_FOOTER = "-----END RSA PRIVATE KEY-----";
     private static final String PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
     private static final String PKCS8_FOOTER = "-----END PRIVATE KEY-----";
+    private static final String CERTIFICATE_HEADER = "-----BEGIN CERTIFICATE-----";
+    private static final String CERTIFICATE_FOOTER = "-----END CERTIFICATE-----";
     private X509Certificate certificate;
     private PrivateKey privateKey;
     private PublicKey publicKey;
@@ -61,8 +64,9 @@ public class CredentialParser {
         publicKey = certificate.getPublicKey();
     }
 
-    public void parsePEMCredentials(String certificateFile, String privateKeyFile) throws CertificateException, FileNotFoundException {
-        certificate = parsePEMCertificate(certificateFile);
+    public void parsePEMCredentials(String certificateFile, String privateKeyFile)
+            throws CertificateException, FileNotFoundException {
+        certificate = parsePEMCertificates(certificateFile).get(0);
         if (certificate.getIssuerX500Principal().equals(certificate.getSubjectX500Principal())) {
             throw new CertificateException("Signing certificate cannot be self-signed!");
         }
@@ -70,24 +74,44 @@ public class CredentialParser {
         publicKey = certificate.getPublicKey();
     }
 
+    /**
+     * This method extracts certificate bytes from a string. The bytes are assumed to be
+     * PEM format, and a header and footer are concatenated with the input string to
+     * facilitate proper parsing.
+     * @param pemString the input string
+     * @return an X509Certificate created from the string
+     * @throws CertificateException if instantiating the CertificateFactory errors
+     */
+    public X509Certificate parseCertFromPEMString(String pemString) throws CertificateException {
+        try {
+            CertificateFactory factory = CertificateFactory.getInstance(X509);
+            InputStream inputStream = new ByteArrayInputStream((CERTIFICATE_HEADER
+                                                                + pemString
+                                                                + CERTIFICATE_FOOTER).getBytes());
+            return (X509Certificate) factory.generateCertificate(inputStream);
+        } catch (CertificateException e) {
+            throw e;
+        }
+    }
+
     /**
      * This method returns the X509Certificate object from a PEM certificate file.
      * @param certificateFile
      * @return
      * @throws FileNotFoundException
      */
-    public X509Certificate parseCertFromPEM(String certificateFile) throws FileNotFoundException {
-        return parsePEMCertificate(certificateFile);
+    public List<X509Certificate> parseCertsFromPEM(String certificateFile)
+            throws FileNotFoundException {
+        return parsePEMCertificates(certificateFile);
     }
 
     /**
      * This method returns the X509Certificate found in a PEM file.
-     * @param filename
-     * @return
-     * @throws FileNotFoundException
+     * @param filename pem file
+     * @return a list containing all X509Certificates extracted
      */
-    private X509Certificate parsePEMCertificate(String filename) throws FileNotFoundException {
-        X509Certificate certificate = null;
+    private List<X509Certificate> parsePEMCertificates(String filename) {
+        List<X509Certificate> certificates = null;
         FileInputStream fis = null;
         BufferedInputStream bis = null;
         try {
@@ -96,9 +120,12 @@ public class CredentialParser {
             CertificateFactory certificateFactory = CertificateFactory.getInstance(X509);
 
             while (bis.available() > 0) {
-                certificate = (X509Certificate) certificateFactory.generateCertificate(bis);
+                certificates = (List<X509Certificate>) certificateFactory.generateCertificates(bis);
             }
 
+            if (certificates.size() < 1) {
+                System.out.println("ERROR: No certificates parsed from " + filename);
+            }
             bis.close();
         } catch (CertificateException e) {
             System.out.println("Error in certificate factory: " + e.getMessage());
@@ -117,7 +144,7 @@ public class CredentialParser {
             }
         }
 
-        return certificate;
+        return certificates;
     }
 
     /**
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
index 56c911e0..73cda086 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
@@ -3,7 +3,6 @@ package hirs.swid;
 import hirs.swid.utils.Commander;
 import com.beust.jcommander.JCommander;
 
-import java.io.FileNotFoundException;
 import java.io.IOException;
 
 public class Main {
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
index 7c580dae..a2eb1b83 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
@@ -1,11 +1,13 @@
 package hirs.swid;
 
 import hirs.swid.utils.HashSwid;
+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.SAXException;
 
+import javax.security.auth.x500.X500Principal;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.UnmarshalException;
@@ -35,10 +37,16 @@ import javax.xml.validation.SchemaFactory;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.security.InvalidKeyException;
 import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
 import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * This class handles validating base Reference Integrity Manifest files.
@@ -47,25 +55,39 @@ public class SwidTagValidator {
     private Unmarshaller unmarshaller;
     private String rimEventLog;
     private String certificateFile;
+    private String trustStore;
 
     /**
      * Setter for rimel file path.
-     * @param rimEventLog
+     * @param rimEventLog the rimel file
      */
     public void setRimEventLog(String rimEventLog) {
         this.rimEventLog = rimEventLog;
     }
 
+    /**
+     * Setter for signing cert file.
+     * @param certificateFile the signing cert
+     */
     public void setCertificateFile(String certificateFile) {
         this.certificateFile = certificateFile;
     }
 
+    /**
+     * Setter for the truststore file path.
+     * @param trustStore the truststore
+     */
+    public void setTrustStore(String trustStore) {
+        this.trustStore = trustStore;
+    }
+
     public SwidTagValidator() {
         try {
             JAXBContext jaxbContext = JAXBContext.newInstance(SwidTagConstants.SCHEMA_PACKAGE);
             unmarshaller = jaxbContext.createUnmarshaller();
             rimEventLog = "";
             certificateFile = "";
+            trustStore = SwidTagConstants.DEFAULT_KEYSTORE_FILE;
         } catch (JAXBException e) {
             System.out.println("Error initializing JAXBContext: " + e.getMessage());
         }
@@ -119,6 +141,8 @@ public class SwidTagValidator {
      */
     private boolean validateSignedXMLDocument(Document doc) {
         DOMValidateContext context = null;
+        CredentialParser cp = new CredentialParser();
+        X509Certificate signingCert = null;
         boolean isValid = false;
         try {
             NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
@@ -127,14 +151,14 @@ public class SwidTagValidator {
             }
             NodeList embeddedCert = doc.getElementsByTagName("X509Data");
             if (embeddedCert.getLength() > 0) {
-                context = new DOMValidateContext(new SwidTagValidator.X509KeySelector(), nodes.item(0));
+                context = new DOMValidateContext(new X509KeySelector(), nodes.item(0));
+                signingCert = cp.parseCertFromPEMString(embeddedCert.item(1).getTextContent());
             } else {
-                CredentialParser cp = new CredentialParser();
                 if (!certificateFile.isEmpty()) {
-                    X509Certificate certificate = cp.parseCertFromPEM(certificateFile);
-                    cp.setCertificate(certificate);
+                    signingCert = cp.parseCertsFromPEM(certificateFile).get(0);
+                    cp.setCertificate(signingCert);
                     System.out.println(cp.getCertificateAuthorityInfoAccess());
-                    context = new DOMValidateContext(certificate.getPublicKey(), nodes.item(0));
+                    context = new DOMValidateContext(signingCert.getPublicKey(), nodes.item(0));
                 } else {
                     System.out.println("Signing certificate not found for validation!");
                     System.exit(1);
@@ -142,7 +166,8 @@ public class SwidTagValidator {
             }
             XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
             XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
-            isValid = signature.validate(context);
+            isValid = signature.validate(context) && validateCertChain(signingCert,
+                                                    cp.parseCertsFromPEM(trustStore));
         } catch (MarshalException | XMLSignatureException e) {
             System.out.println(e.getMessage());
         } catch (Exception e) {
@@ -152,6 +177,105 @@ public class SwidTagValidator {
         return isValid;
     }
 
+    /**
+     * This method validates the cert chain for a given certificate. The truststore is iterated
+     * over until a root CA is found. If a root CA is not found an error is returned describing
+     * the problem with validation.
+     * @param cert the certificate at the start of the chain
+     * @param trustStore the collection from which to find the chain of intermediate and root CAs
+     * @return true if the chain is valid; the false case throws the exception below
+     * @throws Exception if a valid chain is not found in the truststore
+     */
+    private boolean validateCertChain(final X509Certificate cert,
+                                      final List<X509Certificate> trustStore)
+                                                            throws Exception {
+        if (cert == null || trustStore == null) {
+            throw new Exception("Null certificate or truststore received");
+        } else if (trustStore.size() == 0) {
+            throw new Exception("Truststore is empty");
+        }
+
+        final String INT_CA_ERROR = "Intermediate CA found, searching for root CA";
+        String errorMessage = "";
+        X509Certificate startOfChain = cert;
+        do {
+            for (X509Certificate trustedCert : trustStore) {
+                boolean isIssuer = areYouMyIssuer(startOfChain, trustedCert);
+                boolean isSigner = areYouMySigner(startOfChain, trustedCert);
+                if (isIssuer && isSigner) {
+                    if (isSelfSigned(trustedCert)) {
+                        return true;
+                    } else {
+                        startOfChain = trustedCert;
+                        errorMessage = INT_CA_ERROR;
+                        break;
+                    }
+                } else {
+                    if (!isIssuer) {
+                        errorMessage = "Issuer cert not found";
+                    } else if (!isSigner) {
+                        errorMessage = "Signing cert not found";
+                    }
+                }
+            }
+        } while (errorMessage.equals(INT_CA_ERROR));
+
+        throw new Exception(errorMessage);
+    }
+
+    /**
+     * This method checks if cert's issuerDN matches issuer's subjectDN.
+     * @param cert the signed certificate
+     * @param issuer the signing certificate
+     * @return true if they match, false if not
+     * @throws Exception if either argument is null
+     */
+    private boolean areYouMyIssuer(final X509Certificate cert, final X509Certificate issuer)
+                                                                            throws Exception {
+        if (cert == null || issuer == null) {
+            throw new Exception("Cannot verify issuer, null certificate received");
+        }
+        X500Principal issuerDN = new X500Principal(cert.getIssuerX500Principal().getName());
+        return issuer.getSubjectX500Principal().equals(issuerDN);
+    }
+
+    /**
+     * This method checks if cert's signature matches signer's public key.
+     * @param cert the signed certificate
+     * @param signer the signing certificate
+     * @return true if they match
+     * @throws Exception if an error occurs or there is no match
+     */
+    private boolean areYouMySigner(final X509Certificate cert, final X509Certificate signer)
+                                                                            throws Exception {
+        if (cert == null || signer == null) {
+            throw new Exception("Cannot verify signature, null certificate received");
+        }
+        try {
+            cert.verify(signer.getPublicKey(), BouncyCastleProvider.PROVIDER_NAME);
+            return true;
+        } catch (NoSuchAlgorithmException e) {
+            throw new Exception("Signing algorithm in signing cert not supported");
+        } catch (InvalidKeyException e) {
+            throw new Exception("Signing certificate key does not match signature");
+        } catch (NoSuchProviderException e) {
+            throw new Exception("Error with BouncyCastleProvider: " + e.getMessage());
+        } catch (SignatureException e) {
+            throw new Exception("Error with signature: " + e.getMessage());
+        } catch (CertificateException e) {
+            throw new Exception("Encoding error: " + e.getMessage());
+        }
+    }
+
+    /**
+     * This method checks if a given certificate is self signed or not.
+     * @param cert the cert to check
+     * @return true if self signed, false if not
+     */
+    private boolean isSelfSigned(final X509Certificate cert) {
+        return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal());
+    }
+
     public class X509KeySelector extends KeySelector {
         public KeySelectorResult select(KeyInfo keyinfo,
                                         KeySelector.Purpose purpose,

From cfd04ae15a7c39e2743f7e18e5579ee4d63df76a Mon Sep 17 00:00:00 2001
From: chubtub <43381989+chubtub@users.noreply.github.com>
Date: Tue, 6 Jul 2021 08:10:10 -0400
Subject: [PATCH 2/5] Rename keystore to truststore. Read truststore file for
 validation if given.

---
 .../main/java/hirs/swid/CredentialParser.java |  3 ++
 .../src/main/java/hirs/swid/Main.java         | 14 +++--
 .../main/java/hirs/swid/SwidTagGateway.java   |  8 +--
 .../main/java/hirs/swid/SwidTagValidator.java |  9 ++++
 .../main/java/hirs/swid/utils/Commander.java  | 51 ++++---------------
 .../java/hirs/swid/TestSwidTagGateway.java    |  6 +--
 .../test/resources/generated_no_cert.swidtag  | 16 +++---
 .../resources/generated_with_cert.swidtag     | 50 +++++++++---------
 8 files changed, 69 insertions(+), 88 deletions(-)

diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
index 707e611b..41e25d56 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
@@ -107,9 +107,12 @@ public class CredentialParser {
 
     /**
      * This method returns the X509Certificate found in a PEM file.
+     * Unchecked typcase warnings are suppressed because the CertificateFactory
+     * implements X509Certificate objects explicitly.
      * @param filename pem file
      * @return a list containing all X509Certificates extracted
      */
+    @SuppressWarnings("unchecked")
     private List<X509Certificate> parsePEMCertificates(String filename) {
         List<X509Certificate> certificates = null;
         FileInputStream fis = null;
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
index 73cda086..60e6cb82 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
@@ -24,6 +24,7 @@ public class Main {
                 String verifyFile = commander.getVerifyFile();
                 String rimel = commander.getRimEventLog();
                 String certificateFile = commander.getPublicCertificate();
+                String trustStore = commander.getTruststoreFile();
                 if (!verifyFile.isEmpty()) {
                     if (!rimel.isEmpty()) {
                         validator.setRimEventLog(rimel);
@@ -31,6 +32,9 @@ public class Main {
                     if (!certificateFile.isEmpty()) {
                         validator.setCertificateFile(certificateFile);
                     }
+                    if (!trustStore.isEmpty()) {
+                        validator.setTrustStore(trustStore);
+                    }
                     try {
                         validator.validateSwidTag(verifyFile);
                     } catch (IOException e) {
@@ -46,7 +50,7 @@ public class Main {
                 System.out.println(commander.toString());
                 String createType = commander.getCreateType().toUpperCase();
                 String attributesFile = commander.getAttributesFile();
-                String jksKeystoreFile = commander.getKeystoreFile();
+                String jksTruststoreFile = commander.getTruststoreFile();
                 String certificateFile = commander.getPublicCertificate();
                 String privateKeyFile = commander.getPrivateKeyFile();
                 String rimEventLog = commander.getRimEventLog();
@@ -55,16 +59,16 @@ public class Main {
                         if (!attributesFile.isEmpty()) {
                             gateway.setAttributesFile(attributesFile);
                         }
-                        if (!jksKeystoreFile.isEmpty()) {
+                        if (!jksTruststoreFile.isEmpty()) {
                             gateway.setDefaultCredentials(true);
-                            gateway.setJksKeystoreFile(jksKeystoreFile);
+                            gateway.setJksTruststoreFile(jksTruststoreFile);
                         } else if (!certificateFile.isEmpty() && !privateKeyFile.isEmpty()) {
                             gateway.setDefaultCredentials(false);
                             gateway.setPemCertificateFile(certificateFile);
                             gateway.setPemPrivateKeyFile(privateKeyFile);
                         } else {
                             gateway.setDefaultCredentials(true);
-                            gateway.setJksKeystoreFile(SwidTagConstants.DEFAULT_KEYSTORE_FILE);
+                            gateway.setJksTruststoreFile(SwidTagConstants.DEFAULT_KEYSTORE_FILE);
                         }
                         if (rimEventLog.isEmpty()) {
                             System.out.println("Error: a support RIM is required!");
@@ -74,6 +78,8 @@ public class Main {
                         }
                         gateway.generateSwidTag(commander.getOutFile());
                         break;
+                    default:
+                        System.out.println("No create type given, nothing to do");
                 }
             }
         }
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 46a90026..8d76241e 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
@@ -80,7 +80,7 @@ public class SwidTagGateway {
     private Marshaller marshaller;
     private String attributesFile;
     private boolean defaultCredentials;
-    private String jksKeystoreFile;
+    private String jksTruststoreFile;
     private String pemPrivateKeyFile;
     private String pemCertificateFile;
     private String rimEventLog;
@@ -120,9 +120,9 @@ public class SwidTagGateway {
 
     /**
      * Setter for JKS keystore file
-     * @param jksKeystoreFile
+     * @param jksTruststoreFile
      */
-    public void setJksKeystoreFile(String jksKeystoreFile) { this.jksKeystoreFile = jksKeystoreFile; }
+    public void setJksTruststoreFile(String jksTruststoreFile) { this.jksTruststoreFile = jksTruststoreFile; }
 
     /**
      * Setter for private key file in PEM format
@@ -440,7 +440,7 @@ public class SwidTagGateway {
             PublicKey publicKey;
             CredentialParser cp = new CredentialParser();
             if (defaultCredentials) {
-                cp.parseJKSCredentials(jksKeystoreFile);
+                cp.parseJKSCredentials(jksTruststoreFile);
                 privateKey = cp.getPrivateKey();
                 publicKey = cp.getPublicKey();
                 KeyName keyName = kiFactory.newKeyName(cp.getCertificateSubjectKeyIdentifier());
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
index a2eb1b83..c12f2a86 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
@@ -42,6 +42,7 @@ import java.security.Key;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.PublicKey;
+import java.security.Security;
 import java.security.SignatureException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
@@ -57,6 +58,14 @@ public class SwidTagValidator {
     private String certificateFile;
     private String trustStore;
 
+    /**
+     * Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
+     * class expects it to be available.
+     */
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
     /**
      * Setter for rimel file path.
      * @param rimEventLog the rimel file
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
index d18282e5..70bbd3a9 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
@@ -1,11 +1,5 @@
 package hirs.swid.utils;
 
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.InvalidPathException;
-import java.nio.file.Paths;
-
 import com.beust.jcommander.Parameter;
 import hirs.swid.SwidTagConstants;
 
@@ -29,9 +23,9 @@ public class Commander {
     @Parameter(names = {"-v", "--verify <path>"}, order = 3,
             description = "Specify a RIM file to verify.")
     private String verifyFile = "";
-    @Parameter(names = {"--keystore <path>"}, order = 4,
-            description = "JKS keystore containing a private key to sign the base RIM created by the create function.")
-    private String keystoreFile = "";
+    @Parameter(names = {"-t", "--truststore <path>"}, order = 4,
+            description = "PEM truststore to sign the base RIM created.")
+    private String truststoreFile = "";
     @Parameter(names = {"-k", "--privateKeyFile <path>"}, order = 5,
             description = "File containing the private key used to sign the base RIM created by the create function.")
     private String privateKeyFile = "";
@@ -42,17 +36,7 @@ public class Commander {
     @Parameter(names = {"-l", "--rimel <path>"}, order = 7,
             description = "The TCG eventlog file to use as a support RIM. By default the last system eventlog will be used.")
     private String rimEventLog = "";
-/*
-    @Parameter(names = {"-t", "--rimpcr <path>"}, order = 7,
-            description = "The file containing TPM PCR values to use as a support RIM. By default the current platform TPM will be used.")
-    private String rimPcrs = "";
-    //@Parameter(names = {}, order = 8, description = "")
-    private String toBeSigned = "";
-    @Parameter(names = {"-s", "--addSignatureData <originalBaseRIM> <signatureFile> <outputFile>"}, order = 8,
-            description = "The signature data in <signatureFile> will be combined with the data in <originalBaseRIM>" +
-                    "and written to <outputFile>, or will overwrite <originalBaseRIM> if <outputFile> is not given.")
-    private String signatureData = "";
-*/
+
     public boolean isHelp() {
         return help;
     }
@@ -73,7 +57,7 @@ public class Commander {
         return verifyFile;
     }
 
-    public String getKeystoreFile() { return keystoreFile; }
+    public String getTruststoreFile() { return truststoreFile; }
 
     public String getPrivateKeyFile() {
         return privateKeyFile;
@@ -84,19 +68,7 @@ public class Commander {
     }
 
     public String getRimEventLog() { return rimEventLog; }
-/*
-    public String getRimPcrs() {
-        return rimPcrs;
-    }
 
-    public String getToBeSigned() {
-        return toBeSigned;
-    }
-
-    public String getSignatureData() {
-        return signatureData;
-    }
-*/
     public String printHelpExamples() {
         StringBuilder sb = new StringBuilder();
         sb.append("Create a base RIM using the values in attributes.json; " +
@@ -108,8 +80,8 @@ public class Commander {
         sb.append("\t\t-c base -l support_rim.bin -k privateKey.pem -p cert.pem\n\n\n");
         sb.append("Validate a base RIM using an external support RIM to override the payload file:\n\n");
         sb.append("\t\t-v base_rim.swidtag -l support_rim.bin\n\n\n");
-        sb.append("Validate a base RIM with an external cert:\n\n");
-        sb.append("\t\t-v base_rim.swidtag -p signing_cert.pem\n\n\n");
+        sb.append("Validate a base RIM (with an embedded cert) with a PEM truststore:\n\n");
+        sb.append("\t\t-v base_rim.swidtag -t ca.crt\n\n\n");
 
 
         return sb.toString();
@@ -120,8 +92,8 @@ public class Commander {
         sb.append("Using attributes file: " + this.getAttributesFile() + System.lineSeparator());
         sb.append("Write to: " + this.getOutFile() + System.lineSeparator());
         sb.append("Verify file: " + this.getVerifyFile() + System.lineSeparator());
-        if (!this.getKeystoreFile().isEmpty()) {
-            sb.append("Keystore file: " + this.getKeystoreFile() + System.lineSeparator());
+        if (!this.getTruststoreFile().isEmpty()) {
+            sb.append("Truststore file: " + this.getTruststoreFile() + System.lineSeparator());
         } else if (!this.getPrivateKeyFile().isEmpty() &&
                     !this.getPublicCertificate().isEmpty()) {
             sb.append("Private key file: " + this.getPrivateKeyFile() + System.lineSeparator());
@@ -131,11 +103,6 @@ public class Commander {
                     + System.lineSeparator());
         }
         sb.append("Event log support RIM: " + this.getRimEventLog() + System.lineSeparator());
-/*
-        sb.append("TPM PCRs support RIM: " + getRimPcrs() + System.lineSeparator());
-        sb.append("Base RIM to be signed: " + getToBeSigned() + System.lineSeparator());
-        sb.append("External signature file: " + getSignatureData() + System.lineSeparator());
-*/
         return sb.toString();
     }
 }
diff --git a/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java b/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java
index 554f3ca5..9bf58ac8 100644
--- a/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java
+++ b/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java
@@ -1,13 +1,9 @@
 package hirs.swid;
 
-import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.file.Paths;
-import java.util.Scanner;
-import java.net.URISyntaxException;
 
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
@@ -65,7 +61,7 @@ public class TestSwidTagGateway {
 	@Test
 	public void testCreateBaseWithoutCert() {
 		gateway.setDefaultCredentials(true);
-		gateway.setJksKeystoreFile(JKS_KEYSTORE_FILE);
+		gateway.setJksTruststoreFile(JKS_KEYSTORE_FILE);
 		gateway.generateSwidTag(DEFAULT_OUTPUT);
 		expectedFile = TestSwidTagGateway.class.getClassLoader().getResourceAsStream(DEFAULT_NO_CERT);
 		Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT));
diff --git a/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag b/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag
index 51a45d76..7fb01eee 100644
--- a/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag
+++ b/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag
@@ -20,19 +20,19 @@
         <DigestValue>97uWB7zSsO5WaGbrcQrlKd1Bju0aDTjK1/ktUYBje8A=</DigestValue>
       </Reference>
     </SignedInfo>
-    <SignatureValue>N1YtTeo2Ryuj+CtlXIpICEay+ni7vt8+4J7tAsYpa3efnLwtea69PIqEylPWm9LdA8Eo8XDdpgxV
-7h3hi2LTOU+Wxq3bLiLamo99T1EtIwl+ZPcOv8bsfEkmShHdMC0dlfcj6r7x4tc0XkNAhhJgfRNz
-FsmPWKJb6FYcsHFbHO/Uw1hSokbAGcWWTshEOqvKHMa8UVkrFMUPnrnMtdyJqZlhDBrZHNi4rWth
-8TjlUnQVSCF9s9I04FxJ1cUAdeVMHtXKM8Pvjv68PaJMJK73dW5Yd3SbcgoKLesf/HPWeeZL0rr4
+    <SignatureValue>N1YtTeo2Ryuj+CtlXIpICEay+ni7vt8+4J7tAsYpa3efnLwtea69PIqEylPWm9LdA8Eo8XDdpgxV&#13;
+7h3hi2LTOU+Wxq3bLiLamo99T1EtIwl+ZPcOv8bsfEkmShHdMC0dlfcj6r7x4tc0XkNAhhJgfRNz&#13;
+FsmPWKJb6FYcsHFbHO/Uw1hSokbAGcWWTshEOqvKHMa8UVkrFMUPnrnMtdyJqZlhDBrZHNi4rWth&#13;
+8TjlUnQVSCF9s9I04FxJ1cUAdeVMHtXKM8Pvjv68PaJMJK73dW5Yd3SbcgoKLesf/HPWeeZL0rr4&#13;
 TNjlqJ/wq61Ons45MFG9bIscVbnd+XxFHx8Skw==</SignatureValue>
     <KeyInfo>
       <KeyName>2fdeb8e7d030a2209daa01861a964fedecf2bcc1</KeyName>
       <KeyValue>
         <RSAKeyValue>
-          <Modulus>p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx
-xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9
-dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q
-otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW
+          <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>
diff --git a/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag b/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag
index 38a0cf0a..313cae3a 100644
--- a/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag
+++ b/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag
@@ -20,39 +20,39 @@
         <DigestValue>97uWB7zSsO5WaGbrcQrlKd1Bju0aDTjK1/ktUYBje8A=</DigestValue>
       </Reference>
     </SignedInfo>
-    <SignatureValue>N1YtTeo2Ryuj+CtlXIpICEay+ni7vt8+4J7tAsYpa3efnLwtea69PIqEylPWm9LdA8Eo8XDdpgxV
-7h3hi2LTOU+Wxq3bLiLamo99T1EtIwl+ZPcOv8bsfEkmShHdMC0dlfcj6r7x4tc0XkNAhhJgfRNz
-FsmPWKJb6FYcsHFbHO/Uw1hSokbAGcWWTshEOqvKHMa8UVkrFMUPnrnMtdyJqZlhDBrZHNi4rWth
-8TjlUnQVSCF9s9I04FxJ1cUAdeVMHtXKM8Pvjv68PaJMJK73dW5Yd3SbcgoKLesf/HPWeeZL0rr4
+    <SignatureValue>N1YtTeo2Ryuj+CtlXIpICEay+ni7vt8+4J7tAsYpa3efnLwtea69PIqEylPWm9LdA8Eo8XDdpgxV&#13;
+7h3hi2LTOU+Wxq3bLiLamo99T1EtIwl+ZPcOv8bsfEkmShHdMC0dlfcj6r7x4tc0XkNAhhJgfRNz&#13;
+FsmPWKJb6FYcsHFbHO/Uw1hSokbAGcWWTshEOqvKHMa8UVkrFMUPnrnMtdyJqZlhDBrZHNi4rWth&#13;
+8TjlUnQVSCF9s9I04FxJ1cUAdeVMHtXKM8Pvjv68PaJMJK73dW5Yd3SbcgoKLesf/HPWeeZL0rr4&#13;
 TNjlqJ/wq61Ons45MFG9bIscVbnd+XxFHx8Skw==</SignatureValue>
     <KeyInfo>
       <X509Data>
         <X509SubjectName>CN=example.RIM.signer,OU=PCClient,O=Example,ST=VA,C=US</X509SubjectName>
-        <X509Certificate>MIID2jCCAsKgAwIBAgIJAP0uwoNdwZDFMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAlVTMQsw
-CQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxEjAQBgNVBAMM
-CUV4YW1wbGVDQTAeFw0yMDA3MjEyMTQ1MDBaFw0zMDA1MzAyMTQ1MDBaMFwxCzAJBgNVBAYTAlVT
-MQswCQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxGzAZBgNV
-BAMMEmV4YW1wbGUuUklNLnNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKd1
-lWGkSRuxAAY2wHag2GVxUk1dZx2PTpfQOflvLeccAVwa8mQhlsRERq+QK8ilj8Xfqs44/nBaccZD
-OjdfIxIUCMfwhGXjxCaqZbgTucNsExDnu4arTGraoAwzHg0cVLiKT/Cxj9NL4dcMgxRXsPdHfXb0
-923C7xYd2t2qfW05umgaj7qeQl6c68CFNsGX4JA8rWFQZvvGx5DGlK4KTcjPuQQINs5fxasNKqLY
-2hq+z82x/rqwr2hmyizD6FpFSyIABPEMPfB036GEhRwu1WEMkq8yIp2jgRUoFYke9pB3ph9pVow0
-Hh4mNFSKD4pP41VSKY1nus83mdkuukPy5o0CAwEAAaOBpzCBpDAdBgNVHQ4EFgQUL96459AwoiCd
-qgGGGpZP7ezyvMEwHwYDVR0jBBgwFoAURqG47dumcV/Q0ud6ijxdbprDljgwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBsAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwNQYIKwYBBQUHAQEEKTAnMCUGCCsGAQUF
-BzAChhlodHRwczovL2V4YW1wbGUuY29tL2NlcnRzMA0GCSqGSIb3DQEBCwUAA4IBAQDpKx5oQlkS
-11cg7Qp58BmCvjCzFpof+qYePooJsD3i5SwKfRTa2CkDMww9qrwBK7G60y7jhe5InKTdqIlVqaji
-5ZImR0QMKTtk7zt9AJ9EaEzKxfDiE/qX34KxNe4ZmbvLH8N+BSujQXMMi56zGjW469Y/rbDMG8uU
-1dq3zqhO5b+dUr1ecdkYLgzxu6O+oWy5JpVibmcjvNezJsUtjc+km2FYm24vU3/fCNzZ2z0EHQES
-cIEQ5OqfpdFrV3De238RhMH6J4xePSidnFpfBc6FrdyDI1A8eRFz36I4xfVL3ZnJP/+j+NE4q6yz
+        <X509Certificate>MIID2jCCAsKgAwIBAgIJAP0uwoNdwZDFMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAlVTMQsw&#13;
+CQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxEjAQBgNVBAMM&#13;
+CUV4YW1wbGVDQTAeFw0yMDA3MjEyMTQ1MDBaFw0zMDA1MzAyMTQ1MDBaMFwxCzAJBgNVBAYTAlVT&#13;
+MQswCQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxGzAZBgNV&#13;
+BAMMEmV4YW1wbGUuUklNLnNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKd1&#13;
+lWGkSRuxAAY2wHag2GVxUk1dZx2PTpfQOflvLeccAVwa8mQhlsRERq+QK8ilj8Xfqs44/nBaccZD&#13;
+OjdfIxIUCMfwhGXjxCaqZbgTucNsExDnu4arTGraoAwzHg0cVLiKT/Cxj9NL4dcMgxRXsPdHfXb0&#13;
+923C7xYd2t2qfW05umgaj7qeQl6c68CFNsGX4JA8rWFQZvvGx5DGlK4KTcjPuQQINs5fxasNKqLY&#13;
+2hq+z82x/rqwr2hmyizD6FpFSyIABPEMPfB036GEhRwu1WEMkq8yIp2jgRUoFYke9pB3ph9pVow0&#13;
+Hh4mNFSKD4pP41VSKY1nus83mdkuukPy5o0CAwEAAaOBpzCBpDAdBgNVHQ4EFgQUL96459AwoiCd&#13;
+qgGGGpZP7ezyvMEwHwYDVR0jBBgwFoAURqG47dumcV/Q0ud6ijxdbprDljgwCQYDVR0TBAIwADAL&#13;
+BgNVHQ8EBAMCBsAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwNQYIKwYBBQUHAQEEKTAnMCUGCCsGAQUF&#13;
+BzAChhlodHRwczovL2V4YW1wbGUuY29tL2NlcnRzMA0GCSqGSIb3DQEBCwUAA4IBAQDpKx5oQlkS&#13;
+11cg7Qp58BmCvjCzFpof+qYePooJsD3i5SwKfRTa2CkDMww9qrwBK7G60y7jhe5InKTdqIlVqaji&#13;
+5ZImR0QMKTtk7zt9AJ9EaEzKxfDiE/qX34KxNe4ZmbvLH8N+BSujQXMMi56zGjW469Y/rbDMG8uU&#13;
+1dq3zqhO5b+dUr1ecdkYLgzxu6O+oWy5JpVibmcjvNezJsUtjc+km2FYm24vU3/fCNzZ2z0EHQES&#13;
+cIEQ5OqfpdFrV3De238RhMH6J4xePSidnFpfBc6FrdyDI1A8eRFz36I4xfVL3ZnJP/+j+NE4q6yz&#13;
 5VGvm0npLO394ZihtsI1sRAR8ORJ</X509Certificate>
       </X509Data>
       <KeyValue>
         <RSAKeyValue>
-          <Modulus>p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx
-xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9
-dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q
-otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW
+          <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>

From ce090558a642f579d3c7d027318085f9ed1428c5 Mon Sep 17 00:00:00 2001
From: chubtub <43381989+chubtub@users.noreply.github.com>
Date: Tue, 13 Jul 2021 10:25:35 -0400
Subject: [PATCH 3/5] Parse public key or signing cert from XML properly.
 Disallow a single cert for validation. Update javadocs

---
 .../main/java/hirs/swid/CredentialParser.java |   2 +
 .../src/main/java/hirs/swid/Main.java         |  14 +-
 .../main/java/hirs/swid/SwidTagValidator.java | 154 ++++++++++++------
 .../main/java/hirs/swid/utils/Commander.java  |  35 ++--
 .../java/hirs/swid/TestSwidTagGateway.java    |   8 +-
 5 files changed, 133 insertions(+), 80 deletions(-)

diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
index 41e25d56..a48472a9 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
@@ -86,7 +86,9 @@ public class CredentialParser {
         try {
             CertificateFactory factory = CertificateFactory.getInstance(X509);
             InputStream inputStream = new ByteArrayInputStream((CERTIFICATE_HEADER
+                                                                + System.lineSeparator()
                                                                 + pemString
+                                                                + System.lineSeparator()
                                                                 + CERTIFICATE_FOOTER).getBytes());
             return (X509Certificate) factory.generateCertificate(inputStream);
         } catch (CertificateException e) {
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
index 60e6cb82..fec6e298 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/Main.java
@@ -29,18 +29,14 @@ public class Main {
                     if (!rimel.isEmpty()) {
                         validator.setRimEventLog(rimel);
                     }
-                    if (!certificateFile.isEmpty()) {
-                        validator.setCertificateFile(certificateFile);
-                    }
                     if (!trustStore.isEmpty()) {
-                        validator.setTrustStore(trustStore);
+                        validator.setTrustStoreFile(trustStore);
                     }
-                    try {
-                        validator.validateSwidTag(verifyFile);
-                    } catch (IOException e) {
-                        System.out.println("Error validating RIM file: " + e.getMessage());
-                        System.exit(1);
+                    if (!certificateFile.isEmpty()) {
+                        System.out.println("A single cert cannot be used for verification. " +
+                                "The signing cert will be searched for in the trust store.");
                     }
+                    validator.validateSwidTag(verifyFile);
                 } else {
                     System.out.println("Need a RIM file to validate!");
                     System.exit(1);
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
index c12f2a86..03d9490f 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
@@ -4,6 +4,7 @@ import hirs.swid.utils.HashSwid;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
@@ -35,10 +36,13 @@ import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.Key;
+import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.PublicKey;
@@ -46,6 +50,10 @@ import java.security.Security;
 import java.security.SignatureException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Arrays;
+import java.util.Base64;
 import java.util.Iterator;
 import java.util.List;
 
@@ -56,7 +64,7 @@ public class SwidTagValidator {
     private Unmarshaller unmarshaller;
     private String rimEventLog;
     private String certificateFile;
-    private String trustStore;
+    private String trustStoreFile;
 
     /**
      * Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
@@ -74,20 +82,12 @@ public class SwidTagValidator {
         this.rimEventLog = rimEventLog;
     }
 
-    /**
-     * Setter for signing cert file.
-     * @param certificateFile the signing cert
-     */
-    public void setCertificateFile(String certificateFile) {
-        this.certificateFile = certificateFile;
-    }
-
     /**
      * Setter for the truststore file path.
-     * @param trustStore the truststore
+     * @param trustStoreFile the truststore
      */
-    public void setTrustStore(String trustStore) {
-        this.trustStore = trustStore;
+    public void setTrustStoreFile(String trustStoreFile) {
+        this.trustStoreFile = trustStoreFile;
     }
 
     public SwidTagValidator() {
@@ -96,7 +96,7 @@ public class SwidTagValidator {
             unmarshaller = jaxbContext.createUnmarshaller();
             rimEventLog = "";
             certificateFile = "";
-            trustStore = SwidTagConstants.DEFAULT_KEYSTORE_FILE;
+            trustStoreFile = SwidTagConstants.DEFAULT_KEYSTORE_FILE;
         } catch (JAXBException e) {
             System.out.println("Error initializing JAXBContext: " + e.getMessage());
         }
@@ -108,7 +108,7 @@ public class SwidTagValidator {
      *
      * @param path the location of the file to be validated
      */
-    public boolean validateSwidTag(String path) throws IOException {
+    public boolean validateSwidTag(String path) {
         Document document = unmarshallSwidTag(path);
         Element softwareIdentity = (Element) document.getElementsByTagName("SoftwareIdentity").item(0);
         StringBuilder si = new StringBuilder("Base RIM detected:\n");
@@ -144,55 +144,94 @@ public class SwidTagValidator {
     }
 
     /**
-     * This method validates a Document with a signature element.
-     *
-     * @param doc
+     * This method validates a signed XML document.
+     * First, the signing certificate is either parsed from the embedded X509Certificate element or
+     * generated from the Modulus and Exponent elements.
+     * Next, the signature is inspected for two things:
+     * 1. valid signature
+     * 2. valid certificate chain
+     * @param doc XML document
+     * @return true if both the signature and cert chain are valid; false otherwise
      */
     private boolean validateSignedXMLDocument(Document doc) {
-        DOMValidateContext context = null;
-        CredentialParser cp = new CredentialParser();
-        X509Certificate signingCert = null;
-        boolean isValid = false;
         try {
+            DOMValidateContext context;
+            CredentialParser cp = new CredentialParser();
+            X509Certificate signingCert = null;
+            List<X509Certificate> trustStore = cp.parseCertsFromPEM(trustStoreFile);
             NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
             if (nodes.getLength() == 0) {
                 throw new Exception("Signature element not found!");
             }
-            NodeList embeddedCert = doc.getElementsByTagName("X509Data");
+            NodeList embeddedCert = doc.getElementsByTagName("X509Certificate");
             if (embeddedCert.getLength() > 0) {
                 context = new DOMValidateContext(new X509KeySelector(), nodes.item(0));
-                signingCert = cp.parseCertFromPEMString(embeddedCert.item(1).getTextContent());
+                signingCert = cp.parseCertFromPEMString(embeddedCert.item(0).getTextContent());
             } else {
-                if (!certificateFile.isEmpty()) {
-                    signingCert = cp.parseCertsFromPEM(certificateFile).get(0);
-                    cp.setCertificate(signingCert);
-                    System.out.println(cp.getCertificateAuthorityInfoAccess());
-                    context = new DOMValidateContext(signingCert.getPublicKey(), nodes.item(0));
-                } else {
+                PublicKey pk = getPKFromKeyValue(doc);
+                for (X509Certificate trustedCert : trustStore) {
+                    if (Arrays.equals(pk.getEncoded(), trustedCert.getPublicKey().getEncoded())) {
+                        signingCert = trustedCert;
+                    }
+                }
+                if (signingCert == null) {
                     System.out.println("Signing certificate not found for validation!");
                     System.exit(1);
                 }
+                context = new DOMValidateContext(signingCert.getPublicKey(), nodes.item(0));
             }
+            cp.setCertificate(signingCert);
+            System.out.println(cp.getCertificateAuthorityInfoAccess());
             XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
             XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
-            isValid = signature.validate(context) && validateCertChain(signingCert,
-                                                    cp.parseCertsFromPEM(trustStore));
+            boolean signatureIsValid = signature.validate(context);
+            boolean certChainIsValid = validateCertChain(signingCert, trustStore);
+            System.out.println("Signature validity: " + signatureIsValid);
+            System.out.println("Cert chain validity: " + certChainIsValid);
+            return signatureIsValid && certChainIsValid;
+        } catch (FileNotFoundException e) {
+            System.out.println("Error parsing truststore: " + e.getMessage());
+        } catch (NoSuchAlgorithmException e) {
+            System.out.println("Error instantiating a KeyFactory to generate pk: "
+                    + e.getMessage());
+        } catch (InvalidKeySpecException e) {
+            System.out.println("Failed to generate a pk from swidtag: " + e.getMessage());
         } catch (MarshalException | XMLSignatureException e) {
             System.out.println(e.getMessage());
         } catch (Exception e) {
             System.out.println(e.getMessage());
         }
 
-        return isValid;
+        return false;
+    }
+
+    /**
+     * This method generates a public key from the modulus and exponent elements
+     * parsed from a signed swidtag.
+     * @param doc Document object containing the swidtag
+     * @return the generated PublicKey object
+     * @throws NoSuchAlgorithmException if the KeyFactory instance fails to instantiate
+     * @throws InvalidKeySpecException if the KeyFactory fails to generate the public key
+     */
+    private PublicKey getPKFromKeyValue(Document doc)
+            throws NoSuchAlgorithmException, InvalidKeySpecException {
+        Node modulusElement = doc.getElementsByTagName("Modulus").item(0);
+        Node exponentElement = doc.getElementsByTagName("Exponent").item(0);
+        BigInteger modulus = new BigInteger(
+                Base64.getMimeDecoder().decode(modulusElement.getTextContent()));
+        BigInteger exponent = new BigInteger(
+                Base64.getMimeDecoder().decode(exponentElement.getTextContent()));
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
+        KeyFactory factory = KeyFactory.getInstance("RSA");
+        return factory.generatePublic(keySpec);
     }
 
     /**
      * This method validates the cert chain for a given certificate. The truststore is iterated
-     * over until a root CA is found. If a root CA is not found an error is returned describing
-     * the problem with validation.
+     * over until a root CA is found, otherwise an error is returned.
      * @param cert the certificate at the start of the chain
-     * @param trustStore the collection from which to find the chain of intermediate and root CAs
-     * @return true if the chain is valid; the false case throws the exception below
+     * @param trustStore from which to find the chain of intermediate and root CAs
+     * @return true if the chain is valid
      * @throws Exception if a valid chain is not found in the truststore
      */
     private boolean validateCertChain(final X509Certificate cert,
@@ -229,7 +268,7 @@ public class SwidTagValidator {
             }
         } while (errorMessage.equals(INT_CA_ERROR));
 
-        throw new Exception(errorMessage);
+        throw new Exception("Error while validating cert chain: " + errorMessage);
     }
 
     /**
@@ -285,11 +324,26 @@ public class SwidTagValidator {
         return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal());
     }
 
+    /**
+     * This internal class handles parsing the public key from a KeyInfo element.
+     */
     public class X509KeySelector extends KeySelector {
-        public KeySelectorResult select(KeyInfo keyinfo,
-                                        KeySelector.Purpose purpose,
-                                        AlgorithmMethod algorithm,
-                                        XMLCryptoContext context) throws KeySelectorException {
+        /**
+         * This method extracts a public key from either an X509Certificate element
+         * or a KeyValue element.  If the public key's algorithm matches the declared
+         * algorithm it is returned in a KeySelecctorResult.
+         * @param keyinfo the KeyInfo element
+         * @param purpose
+         * @param algorithm the encapsulating signature's declared signing algorithm
+         * @param context
+         * @return a KeySelectorResult if the public key's algorithm matches the declared algorithm
+         * @throws KeySelectorException if the algorithms do not match
+         */
+        public KeySelectorResult select(final KeyInfo keyinfo,
+                                        final KeySelector.Purpose purpose,
+                                        final AlgorithmMethod algorithm,
+                                        final XMLCryptoContext context)
+                                        throws KeySelectorException {
             Iterator keyinfoItr = keyinfo.getContent().iterator();
             while(keyinfoItr.hasNext()) {
                 XMLStructure element = (XMLStructure) keyinfoItr.next();
@@ -307,16 +361,18 @@ public class SwidTagValidator {
                     }
                 }
             }
-
             throw new KeySelectorException("No key found!");
         }
 
+        /**
+         * This method checks that the signature and public key algorithms match.
+         * @param uri to match the signature algorithm
+         * @param name to match the public key algorithm
+         * @return true if both match, false otherwise
+         */
         public boolean areAlgorithmsEqual(String uri, String name) {
-            if (uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256) && name.equalsIgnoreCase("RSA")) {
-                return true;
-            } else {
-                return false;
-            }
+            return uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256)
+                    && name.equalsIgnoreCase("RSA");
         }
 
         private class RIMKeySelectorResult implements KeySelectorResult {
@@ -376,8 +432,8 @@ public class SwidTagValidator {
     /**
      * This method strips all whitespace from an xml file, including indents and spaces
      * added for human-readability.
-     * @param path
-     * @return
+     * @param path to the xml file
+     * @return Document object without whitespace
      */
     private Document removeXMLWhitespace(String path) throws IOException {
         TransformerFactory tf = TransformerFactory.newInstance();
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
index 70bbd3a9..2454f299 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
@@ -13,28 +13,31 @@ public class Commander {
     private boolean help;
     @Parameter(names = {"-c", "--create \"base\""}, order = 0,
             description = "The type of RIM to create. A base RIM will be created by default.")
-    private String createType = "";//other possible values: "eventlog" and "pcr"
+    private String createType = "";
     @Parameter(names = {"-a", "--attributes <path>"}, order = 1,
-            description = "The configuration file holding attributes to populate the base RIM with.")
+            description = "The configuration file holding attributes "
+            + "to populate the base RIM with.")
     private String attributesFile = "";
     @Parameter(names = {"-o", "--out <path>"}, order = 2,
-            description = "The file to write the RIM out to. The RIM will be written to stdout by default.")
+            description = "The file to write the RIM out to. "
+            + "The RIM will be written to stdout by default.")
     private String outFile = "";
     @Parameter(names = {"-v", "--verify <path>"}, order = 3,
             description = "Specify a RIM file to verify.")
     private String verifyFile = "";
     @Parameter(names = {"-t", "--truststore <path>"}, order = 4,
-            description = "PEM truststore to sign the base RIM created.")
-    private String truststoreFile = "";
+            description = "The truststore to sign the base RIM created "
+            + "or to validate the signed base RIM.")
+    private String truststoreFile = "/opt/hirs/rimtool/keystore.jks";
     @Parameter(names = {"-k", "--privateKeyFile <path>"}, order = 5,
-            description = "File containing the private key used to sign the base RIM created by the create function.")
+            description = "The private key used to sign the base RIM created by this tool.")
     private String privateKeyFile = "";
     @Parameter(names = {"-p", "--publicCertificate <path>"}, order = 6,
-            description = "The public key certificate used to verify a RIM file or to embed in a signed RIM. " +
-                    "A signed RIM generated by this tool by default will not show the signing certificate without this parameter present.")
+            description = "The public key certificate to embed in the base RIM created by "
+            + "this tool.")
     private String publicCertificate = "";
     @Parameter(names = {"-l", "--rimel <path>"}, order = 7,
-            description = "The TCG eventlog file to use as a support RIM. By default the last system eventlog will be used.")
+            description = "The TCG eventlog file to use as a support RIM.")
     private String rimEventLog = "";
 
     public boolean isHelp() {
@@ -75,15 +78,17 @@ public class Commander {
                 "sign it with the default keystore, alias, and password;\n");
         sb.append("and write the data to base_rim.swidtag:\n\n");
         sb.append("\t\t-c base -a attributes.json -l support_rim.bin -o base_rim.swidtag\n\n\n");
-        sb.append("Create a base RIM using the default attribute values; sign it using privateKey.pem;\n");
-        sb.append("and write the data to console output, to embed cert.pem in the signature block:\n\n");
+        sb.append("Create a base RIM using the default attribute values; ");
+        sb.append("sign it using privateKey.pem; embed cert.pem in the signature block; ");
+        sb.append("and write the data to console output:\n\n");
         sb.append("\t\t-c base -l support_rim.bin -k privateKey.pem -p cert.pem\n\n\n");
-        sb.append("Validate a base RIM using an external support RIM to override the payload file:\n\n");
+        sb.append("Validate a base RIM using an external support RIM to override the ");
+        sb.append("payload file:\n\n");
         sb.append("\t\t-v base_rim.swidtag -l support_rim.bin\n\n\n");
-        sb.append("Validate a base RIM (with an embedded cert) with a PEM truststore:\n\n");
+        sb.append("Validate a base RIM with its own payload file and a PEM truststore ");
+        sb.append("containing the signing cert:\n\n");
         sb.append("\t\t-v base_rim.swidtag -t ca.crt\n\n\n");
 
-
         return sb.toString();
     }
     public String toString() {
@@ -99,7 +104,7 @@ public class Commander {
             sb.append("Private key file: " + this.getPrivateKeyFile() + System.lineSeparator());
             sb.append("Public certificate: " + this.getPublicCertificate() + System.lineSeparator());
         } else {
-            sb.append("Keystore file: default (" + SwidTagConstants.DEFAULT_KEYSTORE_FILE + ")"
+            sb.append("Truststore file: default (" + SwidTagConstants.DEFAULT_KEYSTORE_FILE + ")"
                     + System.lineSeparator());
         }
         sb.append("Event log support RIM: " + this.getRimEventLog() + System.lineSeparator());
diff --git a/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java b/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java
index 9bf58ac8..02826f0a 100644
--- a/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java
+++ b/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java
@@ -75,13 +75,7 @@ public class TestSwidTagGateway {
 	public void testValidateSwidTag() {
 		String filepath = TestSwidTagGateway.class.getClassLoader().getResource(DEFAULT_WITH_CERT).getPath();
 		System.out.println("Validating file at " + filepath);
-	    try {
-	        Assert.assertTrue(validator.validateSwidTag(filepath));
-	    } catch (IOException e) {
-	        Assert.fail("Invalid swidtag!");
-	    } catch (NullPointerException e) {
-	    	Assert.fail("Cannot find file: " + filepath);
-		}
+		Assert.assertTrue(validator.validateSwidTag(filepath));
 	}
 
 	/**

From 8958085b607d16af8755524a2c2ccb74b3c4b4ab Mon Sep 17 00:00:00 2001
From: chubtub <43381989+chubtub@users.noreply.github.com>
Date: Fri, 16 Jul 2021 16:46:31 -0400
Subject: [PATCH 4/5] Search for signing cert by SKID instead of PK

---
 .../main/java/hirs/swid/CredentialParser.java | 19 +++++++++++--
 .../main/java/hirs/swid/SwidTagValidator.java | 27 +++----------------
 2 files changed, 21 insertions(+), 25 deletions(-)

diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
index a48472a9..de208c87 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
@@ -273,8 +273,8 @@ public class CredentialParser {
     }
 
     /**
-     * This method returns the subjectKeyIdentifier from an X509Certificate.
-     * @return
+     * This method returns the subjectKeyIdentifier from the local X509Certificate.
+     * @return the String representation of the subjectKeyIdentifier
      * @throws IOException
      */
     public String getCertificateSubjectKeyIdentifier() throws IOException {
@@ -285,4 +285,19 @@ public class CredentialParser {
         }
         return decodedValue.substring(1);//Drop the # at the beginning of the string
     }
+
+    /**
+     * This method returns the subjectKeyIdentifier from a given X509Certificate.
+     * @param certificate the cert to pull the subjectKeyIdentifier from
+     * @return the String representation of the subjectKeyIdentifier
+     * @throws IOException
+     */
+    public String getCertificateSubjectKeyIdentifier(X509Certificate certificate) throws IOException {
+        String decodedValue = null;
+        byte[] extension = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId());
+        if (extension != null && extension.length > 0) {
+            decodedValue = JcaX509ExtensionUtils.parseExtensionValue(extension).toString();
+        }
+        return decodedValue.substring(1);//Drop the # at the beginning of the string
+    }
 }
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
index 03d9490f..9af5f446 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
@@ -168,10 +168,12 @@ public class SwidTagValidator {
                 context = new DOMValidateContext(new X509KeySelector(), nodes.item(0));
                 signingCert = cp.parseCertFromPEMString(embeddedCert.item(0).getTextContent());
             } else {
-                PublicKey pk = getPKFromKeyValue(doc);
+                String skId = doc.getElementsByTagName("KeyName").item(0).getTextContent();
                 for (X509Certificate trustedCert : trustStore) {
-                    if (Arrays.equals(pk.getEncoded(), trustedCert.getPublicKey().getEncoded())) {
+                    String trustedSkId = cp.getCertificateSubjectKeyIdentifier(trustedCert);
+                    if (skId.equals(trustedSkId)) {
                         signingCert = trustedCert;
+                        break;
                     }
                 }
                 if (signingCert == null) {
@@ -205,27 +207,6 @@ public class SwidTagValidator {
         return false;
     }
 
-    /**
-     * This method generates a public key from the modulus and exponent elements
-     * parsed from a signed swidtag.
-     * @param doc Document object containing the swidtag
-     * @return the generated PublicKey object
-     * @throws NoSuchAlgorithmException if the KeyFactory instance fails to instantiate
-     * @throws InvalidKeySpecException if the KeyFactory fails to generate the public key
-     */
-    private PublicKey getPKFromKeyValue(Document doc)
-            throws NoSuchAlgorithmException, InvalidKeySpecException {
-        Node modulusElement = doc.getElementsByTagName("Modulus").item(0);
-        Node exponentElement = doc.getElementsByTagName("Exponent").item(0);
-        BigInteger modulus = new BigInteger(
-                Base64.getMimeDecoder().decode(modulusElement.getTextContent()));
-        BigInteger exponent = new BigInteger(
-                Base64.getMimeDecoder().decode(exponentElement.getTextContent()));
-        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
-        KeyFactory factory = KeyFactory.getInstance("RSA");
-        return factory.generatePublic(keySpec);
-    }
-
     /**
      * This method validates the cert chain for a given certificate. The truststore is iterated
      * over until a root CA is found, otherwise an error is returned.

From d2d2b9a494ea06b8ada19d6d1cf54c9e5711d7ad Mon Sep 17 00:00:00 2001
From: chubtub <43381989+chubtub@users.noreply.github.com>
Date: Tue, 20 Jul 2021 11:04:38 -0400
Subject: [PATCH 5/5] Remove KeyValue element from signed swidtag. Update error
 message for missing signer cert. Update version number.

---
 tools/tcg_rim_tool/build.gradle                        |  2 +-
 tools/tcg_rim_tool/scripts/rimtool.sh                  |  2 +-
 .../src/main/java/hirs/swid/SwidTagGateway.java        |  7 -------
 .../src/main/java/hirs/swid/SwidTagValidator.java      |  9 +++++++--
 .../src/main/java/hirs/swid/utils/Commander.java       |  2 +-
 .../src/test/resources/generated_no_cert.swidtag       | 10 ----------
 .../src/test/resources/generated_with_cert.swidtag     | 10 ----------
 tools/tcg_rim_tool/tcg_rim_tool.spec                   |  2 +-
 8 files changed, 11 insertions(+), 33 deletions(-)

diff --git a/tools/tcg_rim_tool/build.gradle b/tools/tcg_rim_tool/build.gradle
index 423e0ced..80d26693 100644
--- a/tools/tcg_rim_tool/build.gradle
+++ b/tools/tcg_rim_tool/build.gradle
@@ -1,5 +1,5 @@
 apply plugin: 'java'
-version = '2.0.0'
+version = '2.1.0'
 
 repositories {
 	mavenCentral()
diff --git a/tools/tcg_rim_tool/scripts/rimtool.sh b/tools/tcg_rim_tool/scripts/rimtool.sh
index 8b0fc5b1..fedae5db 100644
--- a/tools/tcg_rim_tool/scripts/rimtool.sh
+++ b/tools/tcg_rim_tool/scripts/rimtool.sh
@@ -3,6 +3,6 @@
 # Calls the the_tcg_rim_tool and passes in parameters
 scriptDir=$(dirname -- "$(readlink -f -- "${BASH_SOURCE[0]}")")
 baseDir=${scriptDir%/*}
-jar="tcg_rim_tool-2.0.0.jar";
+jar="tcg_rim_tool-2.1.0.jar";
 java -jar $baseDir/$jar "$@"
 
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 8d76241e..3de70de2 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
@@ -437,27 +437,22 @@ public class SwidTagGateway {
 
             KeyInfoFactory kiFactory = sigFactory.getKeyInfoFactory();
             PrivateKey privateKey;
-            PublicKey publicKey;
             CredentialParser cp = new CredentialParser();
             if (defaultCredentials) {
                 cp.parseJKSCredentials(jksTruststoreFile);
                 privateKey = cp.getPrivateKey();
-                publicKey = cp.getPublicKey();
                 KeyName keyName = kiFactory.newKeyName(cp.getCertificateSubjectKeyIdentifier());
                 keyInfoElements.add(keyName);
             } else {
                 cp.parsePEMCredentials(pemCertificateFile, pemPrivateKeyFile);
                 X509Certificate certificate = cp.getCertificate();
                 privateKey = cp.getPrivateKey();
-                publicKey = cp.getPublicKey();
                 ArrayList<Object> x509Content = new ArrayList<Object>();
                 x509Content.add(certificate.getSubjectX500Principal().getName());
                 x509Content.add(certificate);
                 X509Data data = kiFactory.newX509Data(x509Content);
                 keyInfoElements.add(data);
             }
-            KeyValue keyValue = kiFactory.newKeyValue(publicKey);
-            keyInfoElements.add(keyValue);
             KeyInfo keyinfo = kiFactory.newKeyInfo(keyInfoElements);
 
             doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
@@ -472,8 +467,6 @@ public class SwidTagGateway {
         } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException |
                         ParserConfigurationException e) {
             System.out.println(e.getMessage());
-        } catch (KeyException e) {
-            System.out.println("Error setting public key in KeyValue: " + e.getMessage());
         } catch (CertificateException e) {
             System.out.println(e.getMessage());
         } catch (JAXBException e) {
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
index 9af5f446..e1313f0f 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/SwidTagValidator.java
@@ -177,7 +177,8 @@ public class SwidTagValidator {
                     }
                 }
                 if (signingCert == null) {
-                    System.out.println("Signing certificate not found for validation!");
+                    System.out.println("Issuer certificate with subject key identifier = "
+                                    + skId + " not found");
                     System.exit(1);
                 }
                 context = new DOMValidateContext(signingCert.getPublicKey(), nodes.item(0));
@@ -290,7 +291,11 @@ public class SwidTagValidator {
         } catch (NoSuchProviderException e) {
             throw new Exception("Error with BouncyCastleProvider: " + e.getMessage());
         } catch (SignatureException e) {
-            throw new Exception("Error with signature: " + e.getMessage());
+            String error = "Error with signature: " + e.getMessage()
+                    + System.lineSeparator()
+                    + "Certificate needed for verification is missing: "
+                    + signer.getSubjectX500Principal().getName();
+            throw new Exception(error);
         } catch (CertificateException e) {
             throw new Exception("Encoding error: " + e.getMessage());
         }
diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
index 2454f299..3893af68 100644
--- a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java
@@ -28,7 +28,7 @@ public class Commander {
     @Parameter(names = {"-t", "--truststore <path>"}, order = 4,
             description = "The truststore to sign the base RIM created "
             + "or to validate the signed base RIM.")
-    private String truststoreFile = "/opt/hirs/rimtool/keystore.jks";
+    private String truststoreFile = "";
     @Parameter(names = {"-k", "--privateKeyFile <path>"}, order = 5,
             description = "The private key used to sign the base RIM created by this tool.")
     private String privateKeyFile = "";
diff --git a/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag b/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag
index 7fb01eee..ea454392 100644
--- a/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag
+++ b/tools/tcg_rim_tool/src/test/resources/generated_no_cert.swidtag
@@ -27,16 +27,6 @@ FsmPWKJb6FYcsHFbHO/Uw1hSokbAGcWWTshEOqvKHMa8UVkrFMUPnrnMtdyJqZlhDBrZHNi4rWth&#13
 TNjlqJ/wq61Ons45MFG9bIscVbnd+XxFHx8Skw==</SignatureValue>
     <KeyInfo>
       <KeyName>2fdeb8e7d030a2209daa01861a964fedecf2bcc1</KeyName>
-      <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>
diff --git a/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag b/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag
index 313cae3a..dc711f3e 100644
--- a/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag
+++ b/tools/tcg_rim_tool/src/test/resources/generated_with_cert.swidtag
@@ -47,16 +47,6 @@ BzAChhlodHRwczovL2V4YW1wbGUuY29tL2NlcnRzMA0GCSqGSIb3DQEBCwUAA4IBAQDpKx5oQlkS&#13
 cIEQ5OqfpdFrV3De238RhMH6J4xePSidnFpfBc6FrdyDI1A8eRFz36I4xfVL3ZnJP/+j+NE4q6yz&#13;
 5VGvm0npLO394ZihtsI1sRAR8ORJ</X509Certificate>
       </X509Data>
-      <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>
diff --git a/tools/tcg_rim_tool/tcg_rim_tool.spec b/tools/tcg_rim_tool/tcg_rim_tool.spec
index 502d3caf..c7ab4843 100644
--- a/tools/tcg_rim_tool/tcg_rim_tool.spec
+++ b/tools/tcg_rim_tool/tcg_rim_tool.spec
@@ -1,5 +1,5 @@
 Name:           tcg_rim_tool
-Version:        2.0.0
+Version:        2.1.0
 Release:        1%{?dist}
 Summary:        A java command-line tool to create PC client root RIM