diff --git a/build.gradle b/build.gradle
index 26d24f74..ae1424e2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -119,7 +119,7 @@ subprojects {
'com.fasterxml.jackson.core:jackson-databind:2.6.3',
'com.fasterxml.jackson.core:jackson-annotations:2.6.3'],
jadira_usertype: 'org.jadira.usertype:usertype.core:4.0.0.GA',
- jcommander: 'com.beust:jcommander:1.35',
+ jcommander: 'com.beust:jcommander:1.72',
joda_time: 'joda-time:joda-time:2.9.4',
jstl: [ 'org.apache.taglibs:taglibs-standard-impl:1.2.5',
'org.apache.taglibs:taglibs-standard-spec:1.2.5'],
diff --git a/tools/tcg_rim_tool/RimSignCert.pem b/tools/tcg_rim_tool/RimSignCert.pem
new file mode 100644
index 00000000..9d37a2fa
--- /dev/null
+++ b/tools/tcg_rim_tool/RimSignCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgIJAPB+r6VBhBn5MA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwI
+UENDbGllbnQxEjAQBgNVBAMMCUV4YW1wbGVDQTAeFw0yMDAzMTExODExMjJaFw0z
+MDAxMTgxODExMjJaMFwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UE
+CgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxGzAZBgNVBAMMEmV4YW1wbGUu
+UklNLnNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKd1lWGk
+SRuxAAY2wHag2GVxUk1dZx2PTpfQOflvLeccAVwa8mQhlsRERq+QK8ilj8Xfqs44
+/nBaccZDOjdfIxIUCMfwhGXjxCaqZbgTucNsExDnu4arTGraoAwzHg0cVLiKT/Cx
+j9NL4dcMgxRXsPdHfXb0923C7xYd2t2qfW05umgaj7qeQl6c68CFNsGX4JA8rWFQ
+ZvvGx5DGlK4KTcjPuQQINs5fxasNKqLY2hq+z82x/rqwr2hmyizD6FpFSyIABPEM
+PfB036GEhRwu1WEMkq8yIp2jgRUoFYke9pB3ph9pVow0Hh4mNFSKD4pP41VSKY1n
+us83mdkuukPy5o0CAwEAAaNvMG0wHQYDVR0OBBYEFC/euOfQMKIgnaoBhhqWT+3s
+8rzBMB8GA1UdIwQYMBaAFEahuO3bpnFf0NLneoo8XW6aw5Y4MAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgbAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUA
+A4IBAQBl2Bu9xpnHCCeeebjx+ILQXJXBd6q5+NQlV3zzBrf0bleZRtsOmsuFvWQo
+KQxsfZuk7QcSvVd/1v8mqwJ0PwbFKQmrhIPWP+iowiBNqpG5PH9YxhpHQ1osOfib
+NLOXMhudIQRY0yAgqQf+MOlXYa0stX8gkgftVBDRutuMKyOTf4a6d8TUcbG2Rnyz
+O/6S9bq4cPDYLqWRBM+aGN8e00UWTKpBl6/1EU8wkJA6WdllK2e8mVkXUPWYyHTZ
+0qQnrYiuLr36ycAznABDzEAoj4tMZbjIAfuscty6Ggzxl1WbyZLI6YzyXALwaYvr
+crTLeyFynlKxuCfDnr1SAHDM65BY
+-----END CERTIFICATE-----
diff --git a/tools/tcg_rim_tool/build.gradle b/tools/tcg_rim_tool/build.gradle
index fd331228..15dc4693 100644
--- a/tools/tcg_rim_tool/build.gradle
+++ b/tools/tcg_rim_tool/build.gradle
@@ -7,6 +7,8 @@ repositories {
dependencies {
compile libs.minimal_json
+ compile libs.jcommander
+ compile libs.bouncy_castle
testCompile libs.testng
}
@@ -17,6 +19,7 @@ jar {
)
}
from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {}
+ exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
}
uploadArchives {
diff --git a/tools/tcg_rim_tool/identity_transform.xslt b/tools/tcg_rim_tool/identity_transform.xslt
new file mode 100644
index 00000000..d249ca61
--- /dev/null
+++ b/tools/tcg_rim_tool/identity_transform.xslt
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/tcg_rim_tool/keystore.jks b/tools/tcg_rim_tool/keystore.jks
index 1102b2c5..2877d7f4 100644
Binary files a/tools/tcg_rim_tool/keystore.jks and b/tools/tcg_rim_tool/keystore.jks differ
diff --git a/tools/tcg_rim_tool/privateRimKey.pem b/tools/tcg_rim_tool/privateRimKey.pem
new file mode 100644
index 00000000..afe282c4
--- /dev/null
+++ b/tools/tcg_rim_tool/privateRimKey.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCndZVhpEkbsQAG
+NsB2oNhlcVJNXWcdj06X0Dn5by3nHAFcGvJkIZbEREavkCvIpY/F36rOOP5wWnHG
+Qzo3XyMSFAjH8IRl48QmqmW4E7nDbBMQ57uGq0xq2qAMMx4NHFS4ik/wsY/TS+HX
+DIMUV7D3R3129Pdtwu8WHdrdqn1tObpoGo+6nkJenOvAhTbBl+CQPK1hUGb7xseQ
+xpSuCk3Iz7kECDbOX8WrDSqi2Noavs/Nsf66sK9oZsosw+haRUsiAATxDD3wdN+h
+hIUcLtVhDJKvMiKdo4EVKBWJHvaQd6YfaVaMNB4eJjRUig+KT+NVUimNZ7rPN5nZ
+LrpD8uaNAgMBAAECggEAcnG8npd9U0x7HMQMcsZoPaPdwHvF/gCzkLNA+8RM1bZh
+A4ZzA5WlCQs0V8Wq9pyXjn7Wp8txsG1PdlT5k2AUgsVoXuR0R4IKyvYHQG9StEjH
+GvWURmwJdLlnSg8hSYqEJ/52taNUDO6+MI8fgiaQDd8w0ryF4OCpLy9GJdnfkGYZ
+Ayemb3USFUdj/S67NVqxnvAfFMM5FqkKGhkoy7wBRgO6eOeJvoTq8LMiPiponwwF
+DW409ZStbrk1f1Oszst/UvFUWA9BdDfeoPmFR61y3eB5zlMQG8Mhr2v5hvkj9TPX
+FU4Fm4EzZ1h/60cdWoP6XYCP7F2NqZ8N8u4UBQNAIQKBgQDcGIw5GJEvRF+FFTTR
+hYatMRn80DGTVjdT32MgajdKx05OWxBmQsFob34fiSnr0wAXPJeDXG4ruMBE2bSk
+EC8rCO08G8ihQoH8x0cvuERe1fpVWk3RWNucVGIiJSEXAIwWrlYZLTfYd5GqBkPE
+OQxxo4MtOyqeHmVH1mOywk9ABQKBgQDCxt95luzqQZV9Xl78QQvOIbjOdHLjY23Z
+yp8sGt9birL/WZ33TCRgmH1e61BdrSqO7Om/ail2Y59XM5UU6kLbDj0IgmOPTsrJ
+JmIVf8r3bKltVUaLePgr4yex7dmtHRH8OkLXKnE0RCO0kCi9kJMB12yE3pWxk+Pu
+zztQd3a66QKBgBNJd2g9deONe01fOVyu9clRhzR3ThDaOkj4R2h8xlGgO4V0R3Ce
+ovIy6vt6epj2yYg/wAs720+rhfXCmijSXj/ILXnZ+W/gMyHimKNe42boG2LFYhJZ
+Vg1R+7OAS3EHlD8ckeDs7Hrkp3gdymx0j1mZ+ZHKIIbwpPFxoRT2IBm9AoGBAI0Z
+bIK0puP8psKvPrgWluq42xwUl7XKLaX8dtqIjQ3PqGP7E8g2TJP9Y7UDWrDB5Xas
+gZi821R8Ts3o/DKukcgGxIgJjP4f4h9dwug4L1yWRxaBFB2tgHqqj/MBjxMtX/4M
+Zqdgg6mNQyBm3lyVAynuWRrX9DE0JYa2cQ2VvVkhAoGBAMBv/oT813w00759PmkO
+Uxv3LXTJuYBbq0Rmga25jN3ow8LrGQdSVg7F/af3I5KUF7mLiegDy1pkRfauyXH7
++WhEqnf86vDrzPpytDMxinWOQZusCqeWHb+nuVTuL3Fv+GxEdwVGYI/7lFJ7B//h
+P5rU93ZoYY7sWcGVqaaEkMRU
+-----END PRIVATE KEY-----
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
new file mode 100644
index 00000000..96f3fe5a
--- /dev/null
+++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/CredentialParser.java
@@ -0,0 +1,213 @@
+package hirs.swid;
+
+import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.util.encoders.Base64;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+/**
+ * This class parses private key, public key, and certificate for use in their respective java.security objects.
+ */
+public class CredentialParser {
+ private static final String X509 = "X.509";
+ private static final String JKS = "JKS";
+ private static final String PEM = "PEM";
+ private static final String PKCS1_HEADER = "-----BEGIN RSA PRIVATE KEY-----";
+ 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 X509Certificate certificate;
+ private PrivateKey privateKey;
+ private PublicKey publicKey;
+
+ public X509Certificate getCertificate() {
+ return certificate;
+ }
+
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ public void parseJKSCredentials() {
+ KeyStore.PrivateKeyEntry privateKeyEntry =
+ parseKeystorePrivateKey(SwidTagConstants.DEFAULT_KEYSTORE_PATH,
+ SwidTagConstants.DEFAULT_PRIVATE_KEY_ALIAS,
+ SwidTagConstants.DEFAULT_KEYSTORE_PASSWORD);
+ certificate = (X509Certificate) privateKeyEntry.getCertificate();
+ privateKey = privateKeyEntry.getPrivateKey();
+ publicKey = certificate.getPublicKey();
+ }
+
+ public void parsePEMCredentials(String certificateFile, String privateKeyFile) throws FileNotFoundException {
+ certificate = parsePEMCertificate(certificateFile);
+ privateKey = parsePEMPrivateKey(privateKeyFile, "RSA");
+ publicKey = certificate.getPublicKey();
+ }
+
+ /**
+ * This method returns the X509Certificate found in a PEM file.
+ * @param filename
+ * @return
+ * @throws FileNotFoundException
+ */
+ private X509Certificate parsePEMCertificate(String filename) throws FileNotFoundException {
+ X509Certificate certificate = null;
+ FileInputStream fis = null;
+ BufferedInputStream bis = null;
+ try {
+ fis = new FileInputStream(filename);
+ bis = new BufferedInputStream(fis);
+ CertificateFactory certificateFactory = CertificateFactory.getInstance(X509);
+
+ while (bis.available() > 0) {
+ certificate = (X509Certificate) certificateFactory.generateCertificate(bis);
+ }
+
+ bis.close();
+ } catch (CertificateException e) {
+ System.out.println("Error in certificate factory: " + e.getMessage());
+ } catch (IOException e) {
+ System.out.println("Error reading from input stream: " + e.getMessage());
+ } finally {
+ try {
+ if (fis != null) {
+ fis.close();
+ }
+ if (bis != null) {
+ bis.close();
+ }
+ } catch (IOException e) {
+ System.out.println("Error closing input stream: " + e.getMessage());
+ }
+ }
+
+ return certificate;
+ }
+
+ /**
+ * This method extracts the private key from a PEM file.
+ * Both PKCS1 and PKCS8 formats are handled.
+ * Algorithm argument is present to allow handling of multiple encryption algorithms,
+ * but for now it is always RSA.
+ * @param filename
+ * @return
+ */
+ private PrivateKey parsePEMPrivateKey(String filename, String algorithm) {
+ PrivateKey privateKey = null;
+ FileInputStream fis = null;
+ DataInputStream dis = null;
+ try {
+ File file = new File(filename);
+ fis = new FileInputStream(file);
+ dis = new DataInputStream(fis);
+ byte[] key = new byte[(int) file.length()];
+ dis.readFully(key);
+ dis.close();
+
+ String privateKeyStr = new String(key);
+ if (privateKeyStr.contains(PKCS1_HEADER)) {
+ privateKey = getPKCS1KeyPair(filename).getPrivate();
+ } else if (privateKeyStr.contains(PKCS8_HEADER)) {
+ privateKeyStr = privateKeyStr.replace(PKCS8_HEADER, "");
+ privateKeyStr = privateKeyStr.replace(PKCS8_FOOTER, "");
+
+ byte[] decodedKey = Base64.decode(privateKeyStr);
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decodedKey);
+ KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
+
+ privateKey = keyFactory.generatePrivate(spec);
+ }
+ } catch (FileNotFoundException e) {
+ System.out.println("Unable to locate private key file: " + filename);
+ } catch (NoSuchAlgorithmException e) {
+ System.out.println("Unable to instantiate KeyFactory with algorithm: " + algorithm);
+ } catch (IOException e) {
+ System.out.println("IOException: " + e.getMessage());
+ } catch (InvalidKeySpecException e) {
+ System.out.println("Error instantiating PKCS8EncodedKeySpec object: " + e.getMessage());
+ } finally {
+ try {
+ if (fis != null) {
+ fis.close();
+ }
+ if (dis != null) {
+ dis.close();
+ }
+ } catch (IOException e) {
+ System.out.println("Error closing input stream: " + e.getMessage());
+ }
+ }
+
+ return privateKey;
+ }
+
+ /**
+ * This method reads a PKCS1 keypair from a PEM file.
+ * @param filename
+ * @return
+ */
+ private KeyPair getPKCS1KeyPair(String filename) throws IOException {
+ Security.addProvider(new BouncyCastleProvider());
+ PEMParser pemParser = new PEMParser(new FileReader(filename));
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
+ KeyPair keyPair = converter.getKeyPair((PEMKeyPair) pemParser.readObject());
+
+ return keyPair;
+ }
+
+ /**
+ * This method returns the private key from a JKS keystore.
+ * @param keystoreFile
+ * @param alias
+ * @param password
+ * @return KeyStore.PrivateKeyEntry
+ */
+ private KeyStore.PrivateKeyEntry parseKeystorePrivateKey(String keystoreFile, String alias, String password) {
+ KeyStore keystore = null;
+ KeyStore.PrivateKeyEntry privateKey = null;
+ try {
+ keystore = KeyStore.getInstance("JKS");
+ keystore.load(new FileInputStream(keystoreFile), password.toCharArray());
+ privateKey = (KeyStore.PrivateKeyEntry) keystore.getEntry(alias,
+ new KeyStore.PasswordProtection(password.toCharArray()));
+ } catch (FileNotFoundException e) {
+ System.out.println("Cannot locate keystore " + keystoreFile);
+ } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableEntryException | CertificateException | IOException e) {
+ e.printStackTrace();
+ }
+
+ return privateKey;
+ }
+
+ /**
+ * Utility method for extracting the subjectKeyIdentifier from an X509Certificate.
+ * The subjectKeyIdentifier is stored as a DER-encoded octet and will be converted to a String.
+ * @return
+ */
+ public String getCertificateSubjectKeyIdentifier() throws IOException {
+ String decodedValue = null;
+ byte[] extension = certificate.getExtensionValue(SwidTagConstants.CERTIFICATE_SUBJECT_KEY_IDENTIFIER);
+ if (extension != null) {
+ decodedValue = JcaX509ExtensionUtils.parseExtensionValue(extension).toString();
+ }
+ //If there is a # symbol at the beginning of the string, remove it
+ if (decodedValue.startsWith("#")) {
+ decodedValue = decodedValue.substring(1);
+ }
+ return decodedValue;
+ }
+}
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 9c83b043..da3baed2 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
@@ -1,50 +1,58 @@
package hirs.swid;
import hirs.swid.utils.Commander;
+import com.beust.jcommander.JCommander;
+
+import java.io.FileNotFoundException;
import java.io.IOException;
-/*
- * Command-line application for generating and validating SWID tags.
- * Input arg: path to *.swidtag file
- *
- * If an argument is given it will be validated against the schema at http://standards.iso.org/iso/19770/-2/2015/schema.xsd
- * If an argument is not given a SWID tag file will be generated.
- */
public class Main {
public static void main(String[] args) {
- Commander commander = new Commander(args);
+ Commander commander = new Commander();
+ JCommander jc = JCommander.newBuilder().addObject(commander).build();
+ jc.parse(args);
SwidTagGateway gateway = new SwidTagGateway();
- if (commander.hasArguments()) {
- // we have arguments to work with
- if (commander.isAttributesGiven()) {
- gateway.setAttributesFile(commander.getAttributesFile());
- }
- if (commander.isKeystoreGiven()) {
- gateway.setKeystoreFile(commander.getKeystore());
- }
- if (commander.isShowCert()) {
- gateway.setShowCert(true);
- }
-
- if (commander.create()) {
- // parsing the arguments detected a create parameter (-c)
- gateway.generateSwidTag(commander.getCreateOutFile());
- }
- if (commander.validate()) {
- // parsing the arguments detected a validation parameter (-v)
- try {
- gateway.validateSwidTag(commander.getValidateFile());
- } catch (IOException e) {
- System.out.println("Unable to validate file: " + e.getMessage());
+ if (commander.isHelp()) {
+ jc.usage();
+ System.out.println(commander.printHelpExamples());
+ } else {
+ if (!commander.getVerifyFile().isEmpty()) {
+ System.out.println(commander.toString());
+ String verifyFile = commander.getVerifyFile();
+ String publicCertificate = commander.getPublicCertificate();
+ if (!verifyFile.isEmpty() && !publicCertificate.isEmpty()) {
+ try {
+ gateway.validateSwidTag(verifyFile);
+ } catch (IOException e) {
+ System.out.println("Error validating RIM file: " + e.getMessage());
+ }
+ } else {
+ System.out.println("Need both a RIM file to validate and a public certificate to validate with!");
}
- }
- if (commander.parse()) {
- try {
- gateway.parsePayload(commander.getParseFile());
- } catch (IOException e) {
- System.out.println("Unable to parse file: " + e.getMessage());
+ } else {
+ System.out.println(commander.toString());
+ String createType = commander.getCreateType().toUpperCase();
+ String attributesFile = commander.getAttributesFile();
+ String certificateFile = commander.getPublicCertificate();
+ String privateKeyFile = commander.getPrivateKeyFile();
+ switch (createType) {
+ case "BASE":
+ if (!attributesFile.isEmpty()) {
+ gateway.setAttributesFile(attributesFile);
+ }
+ if (!certificateFile.isEmpty() && !privateKeyFile.isEmpty()) {
+ gateway.setDefaultCredentials(false);
+ gateway.setPemCertificateFile(certificateFile);
+ gateway.setPemPrivateKeyFile(privateKeyFile);
+ }
+ gateway.generateSwidTag(commander.getOutFile());
+ break;
+ case "EVENTLOG":
+ break;
+ case "PCR":
+ break;
}
}
}
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 bad1a213..1e19a0a5 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
@@ -20,15 +20,10 @@ public class SwidTagConstants {
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
- public static final String SCHEMA_STATEMENT = "ISO/IEC 19770-2:2015 Schema (XSD 1.0) "
- + "- September 2015, see http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
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 HIRS_SWIDTAG_HEADERS = "hirsSwidTagHeader.properties";
- public static final String EXAMPLE_PROPERTIES = "swidExample.properties";
-
public static final String SOFTWARE_IDENTITY = "SoftwareIdentity";
public static final String ENTITY = "Entity";
public static final String LINK = "Link";
@@ -147,48 +142,5 @@ public class SwidTagConstants {
"http://csrc.nist.gov/ns/swid/2015-extensions/1.0",
"pathSeparator", "n8060");
-//Below properties can probably be deleted
- public static final String SOFTWARE_IDENTITY_NAME = "softwareIdentity.name";
- public static final String SOFTWARE_IDENTITY_TAGID = "softwareIdentity.tagId";
- public static final String SOFTWARE_IDENTITY_VERSION = "softwareIdentity.version";
- public static final String SOFTWARE_IDENTITY_CORPUS = "softwareIdentity.corpus";
- public static final String SOFTWARE_IDENTITY_PATCH = "softwareIdentity.patch";
- public static final String SOFTWARE_IDENTITY_SUPPLEMENTAL = "softwareIdentity.supplemental";
-
- public static final String ENTITY_NAME = "entity.name";
- public static final String ENTITY_REGID = "entity.regid";
- public static final String ENTITY_ROLE = "entity.role";
- public static final String ENTITY_THUMBPRINT = "entity.thumbprint";
-
- public static final String LINK_HREF = "link.href";
- public static final String LINK_REL = "link.rel";
-
- public static final String META_PCURILOCAL = "softwareMeta.pcUriLocal";
- public static final String META_BINDINGSPEC = "softwareMeta.bindingSpec";
- public static final String META_BINDINGSPECVERSION = "softwareMeta.bindingSpecVersion";
- public static final String META_PLATFORMMANUFACTURERID = "softwareMeta.platformManufacturerId";
- public static final String META_PLATFORMMANUFACTURERSTR = "softwareMeta.platformManufacturerStr";
- public static final String META_PLATFORMMODEL = "softwareMeta.platformModel";
- public static final String META_COMPONENTCLASS = "softwareMeta.componentClass";
- public static final String META_COMPONENTMANUFACTURER = "softwareMeta.componentManufacturer";
- public static final String META_COMPONENTMANUFACTURERID = "softwareMeta.componentManufacturerId";
- public static final String META_RIMLINKHASH = "softwareMeta.rimLinkHash";
-
- public static final String PAYLOAD_ENVVARPREFIX = "n8060.envvarprefix";
- public static final String PAYLOAD_ENVVARSUFFIX = "n8060.envvarsuffix";
- public static final String PAYLOAD_PATHSEPARATOR = "n8060.pathseparator";
-
- public static final String DIRECTORY_KEY = "directory.key";
- public static final String DIRECTORY_LOCATION = "directory.location";
- public static final String DIRECTORY_NAME = "directory.name";
- public static final String DIRECTORY_ROOT = "directory.root";
- public static final String FILE_KEY = "file.key";
- public static final String FILE_LOCATION = "file.location";
- public static final String FILE_NAME = "file.name";
- public static final String FILE_ROOT = "file.root";
- public static final String FILE_SIZE = "file.size";
- public static final String FILE_VERSION = "file.version";
-
- public static final int PCR_NUMBER = 0;
- public static final int PCR_VALUE = 1;
+ public static final String CERTIFICATE_SUBJECT_KEY_IDENTIFIER = "2.5.29.14";
}
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 8673ae36..4fbe8b52 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
@@ -1,18 +1,19 @@
package hirs.swid;
-import javax.xml.bind.JAXB;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.UnmarshalException;
+import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
@@ -29,7 +30,6 @@ import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
-import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
@@ -37,78 +37,48 @@ import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
-import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
-import javax.xml.crypto.dsig.keyinfo.KeyInfo;
-import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.io.ByteArrayInputStream;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
-import java.io.OutputStream;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
-import java.nio.file.Path;
import java.nio.file.Paths;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.UnrecoverableEntryException;
-import java.security.cert.CertificateException;
+import java.security.*;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Properties;
import java.math.BigInteger;
-import hirs.swid.utils.CsvParser;
-import hirs.swid.utils.HashSwid;
-import hirs.swid.xjc.BaseElement;
-import hirs.swid.xjc.CanonicalizationMethodType;
-import hirs.swid.xjc.DigestMethodType;
import hirs.swid.xjc.Directory;
import hirs.swid.xjc.Entity;
import hirs.swid.xjc.Link;
import hirs.swid.xjc.ObjectFactory;
import hirs.swid.xjc.ResourceCollection;
-import hirs.swid.xjc.ReferenceType;
-import hirs.swid.xjc.SignatureType;
-import hirs.swid.xjc.SignatureValueType;
-import hirs.swid.xjc.SignatureMethodType;
-import hirs.swid.xjc.SignedInfoType;
import hirs.swid.xjc.SoftwareIdentity;
import hirs.swid.xjc.SoftwareMeta;
-import hirs.swid.xjc.TransformType;
-import hirs.swid.xjc.TransformsType;
import com.eclipsesource.json.Json;
import com.eclipsesource.json.JsonObject;
-import com.eclipsesource.json.JsonObject.Member;
-import com.eclipsesource.json.JsonValue;
-import com.eclipsesource.json.Location;
import com.eclipsesource.json.ParseException;
@@ -120,32 +90,16 @@ import com.eclipsesource.json.ParseException;
*/
public class SwidTagGateway {
- private static final QName _DEFAULT_QNAME = new QName(
- "http://www.w3.org/2000/09/xmldsig#", "SHA256", "ds");
- private static final QName _SHA1Value_QNAME = new QName(
- "http://www.w3.org/2000/09/xmldsig#", "SHA1", "ds");
- private static final QName _SHA384Value_QNAME = new QName(
- "http://www.w3.org/2000/09/xmldsig#", "SHA384", "ds");
- private static final QName _SHA512Value_QNAME = new QName(
- "http://www.w3.org/2000/09/xmldsig#", "SHA512", "ds");
private static final QName _SHA256_HASH = new QName(
"http://www.w3.org/2001/04/xmlenc#sha256", "hash", "SHA256");
-
private final ObjectFactory objectFactory = new ObjectFactory();
- private final File generatedFile = new File("generated_swidTag.swidtag");
- private QName hashValue = null;
-
private JAXBContext jaxbContext;
private Marshaller marshaller;
private Unmarshaller unmarshaller;
private String attributesFile;
- /**
- * The keystoreFile is used in signXMLDocument() to pass in the keystore path.
- * The same method requires the keystore password and the alias of the private key,
- * which would need to be passed in if not using the default keystore.
- */
- private String keystoreFile;
- private boolean showCert;
+ private boolean defaultCredentials;
+ private String pemPrivateKeyFile;
+ private String pemCertificateFile;
/**
* Default constructor initializes jaxbcontext, marshaller, and unmarshaller
@@ -156,8 +110,8 @@ public class SwidTagGateway {
marshaller = jaxbContext.createMarshaller();
unmarshaller = jaxbContext.createUnmarshaller();
attributesFile = SwidTagConstants.DEFAULT_ATTRIBUTES_FILE;
- keystoreFile = SwidTagConstants.DEFAULT_KEYSTORE_PATH;
- showCert = false;
+ defaultCredentials = true;
+ pemCertificateFile = "";
} catch (JAXBException e) {
System.out.println("Error initializing jaxbcontext: " + e.getMessage());
}
@@ -172,107 +126,37 @@ public class SwidTagGateway {
}
/**
- * Setter for String holding keystore path
- * @param keystore
+ * Setter for boolean governing signing credentials
+ * @param defaultCredentials
+ * @return
*/
- public void setKeystoreFile(String keystoreFile) {
- this.keystoreFile = keystoreFile;
+ public void setDefaultCredentials(boolean defaultCredentials) {
+ this.defaultCredentials = defaultCredentials;
}
/**
- * Setter for boolean to display certificate block in xml signature
- * @param showCert
+ * Setter for private key file in PEM format
+ * @param pemPrivateKeyFile
*/
- public void setShowCert(boolean showCert) {
- this.showCert = showCert;
+ public void setPemPrivateKeyFile(String pemPrivateKeyFile) {
+ this.pemPrivateKeyFile = pemPrivateKeyFile;
}
- /**
- * default generator method that has no parameters
+ /** Setter for certificate file in PEM format
+ * @param pemCertificateFile
*/
- public void generateSwidTag() {
- generateSwidTag("");
- }
-
- /**
- * This generator method is used by the create method.
- *
- * This method should be updated to incorporate the RIM fields that are implemented
- * in generateSwidTag(final File outputFile) below.
- *
- * @param inputFile - the file in csv format that is used as data
- * @param outputFile - output specific to the given file
- * @param hashType - the optional labeling of the hash type
- */
- public void generateSwidTag(final String inputFile,
- final String outputFile, final String hashType) {
- // create file instances
- File input = new File(inputFile);
- File output = new File(outputFile);
- List tempList = new LinkedList<>();
-
- // I need to go over this again about which needs to be checked.
- if (input.exists()) {
- // parse the csv file
- CsvParser parser = new CsvParser(input);
- for (String line : parser.getContent()) {
- tempList.add(line);
- }
-
- if (hashType.contains("256")) {
- hashValue = _DEFAULT_QNAME;
- } else if (hashType.contains("384")) {
- hashValue = _SHA384Value_QNAME;
- } else if (hashType.contains("512")) {
- hashValue = _SHA512Value_QNAME;
- } else if (hashType.contains("1")) {
- hashValue = _SHA1Value_QNAME;
- } else {
- hashValue = _DEFAULT_QNAME;
- }
-
- // generate a swid tag
- Properties properties = new Properties();
- InputStream is = null;
- try {
- is = SwidTagGateway.class.getClassLoader().getResourceAsStream(SwidTagConstants.HIRS_SWIDTAG_HEADERS);
- properties.load(is);
-
- SoftwareIdentity swidTag = createSwidTag(new JsonObject());
-
- JAXBElement entity = objectFactory.createSoftwareIdentityEntity(createEntity(new JsonObject()));
- swidTag.getEntityOrEvidenceOrLink().add(entity);
-
- // we should have resources, there for we need a collection
- JAXBElement resources = objectFactory.createSoftwareIdentityPayload(createPayload(tempList, hashValue));
- swidTag.getEntityOrEvidenceOrLink().add(resources);
-
- JAXBElement jaxbe = objectFactory.createSoftwareIdentity(swidTag);
- writeSwidTagFile(jaxbe, output);
- } catch (IOException e) {
- System.out.println("Error reading properties file: ");
- e.printStackTrace();
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException ex) {
- // ignore
- }
- }
- }
- }
+ public void setPemCertificateFile(String pemCertificateFile) {
+ this.pemCertificateFile = pemCertificateFile;
}
/**
* This method generates a base RIM from the values in a JSON file.
*
- * @param outputFile
+ * @param filename
*/
public void generateSwidTag(final String filename) {
SoftwareIdentity swidTag = null;
try {
- System.out.println("Reading base rim values from " + attributesFile);
BufferedReader jsonIn = Files.newBufferedReader(Paths.get(attributesFile), StandardCharsets.UTF_8);
JsonObject configProperties = Json.parse(jsonIn).asObject();
//SoftwareIdentity
@@ -318,12 +202,7 @@ public class SwidTagGateway {
}
Document signedSoftwareIdentity = signXMLDocument(objectFactory.createSoftwareIdentity(swidTag));
- System.out.println("Signature core validity: " + validateSignedXMLDocument(signedSoftwareIdentity));
- if (!filename.isEmpty()) {
- writeSwidTagFile(signedSoftwareIdentity, new File(filename));
- } else {
- writeSwidTagFile(signedSoftwareIdentity, generatedFile);
- }
+ writeSwidTagFile(signedSoftwareIdentity, filename);
}
/**
@@ -334,51 +213,33 @@ public class SwidTagGateway {
* @param path the location of the file to be validated
*/
public boolean validateSwidTag(String path) throws IOException {
- JAXBElement jaxbe = unmarshallSwidTag(path);
- SoftwareIdentity swidTag = (SoftwareIdentity) jaxbe.getValue();
- String output = String.format("name: %s;\ntagId: %s\n%s",
- swidTag.getName(), swidTag.getTagId(),
- SwidTagConstants.SCHEMA_STATEMENT);
- System.out.println("SWID Tag found: ");
- System.out.println(output);
+ Document document = unmarshallSwidTag(path);
+ Element softwareIdentity = (Element) document.getElementsByTagName("SoftwareIdentity").item(0);
+ StringBuilder si = new StringBuilder("Base RIM detected:\n");
+ si.append("SoftwareIdentity name: " + softwareIdentity.getAttribute("name") + "\n");
+ si.append("SoftwareIdentity tagId: " + softwareIdentity.getAttribute("tagId") + "\n");
+ System.out.println(si.toString());
+ System.out.println("Signature core validity: " + validateSignedXMLDocument(document));
return true;
}
- /**
- * This method calls the marshal() method that writes the swidtag data to the output file.
- *
- * @param jaxbe
- * @param outputFile
- */
- public void writeSwidTagFile(JAXBElement jaxbe, File outputFile) {
- JAXBContext jaxbContext;
- try {
- jaxbContext = JAXBContext.newInstance(SwidTagConstants.SCHEMA_PACKAGE);
- Marshaller marshaller = jaxbContext.createMarshaller();
- marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
- marshaller.marshal(jaxbe, outputFile);
- } catch (JAXBException e) {
- System.out.println("Error generating xml: ");
- e.printStackTrace();
- }
- }
-
/**
* This method writes a Document object out to the file specified by generatedFile.
*
* @param swidTag
*/
- public void writeSwidTagFile(Document swidTag, File outputFile) {
+ public void writeSwidTagFile(Document swidTag, String output) {
try {
- OutputStream outStream = new FileOutputStream(outputFile);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
Source source = new DOMSource(swidTag);
- System.out.println("Writing to file: " + outputFile.getName());
- transformer.transform(source, new StreamResult(outStream));
- transformer.transform(source, new StreamResult(System.out));
+ if (output.isEmpty()) {
+ transformer.transform(source, new StreamResult(System.out));
+ } else {
+ transformer.transform(source, new StreamResult(new FileOutputStream(output)));
+ }
} catch (FileNotFoundException e) {
System.out.println("Unable to write to file: " + e.getMessage());
} catch (TransformerConfigurationException e) {
@@ -392,7 +253,7 @@ public class SwidTagGateway {
* This method creates SoftwareIdentity element based on the parameters read in from
* a properties file.
*
- * @param properties the Properties object containing parameters from file
+ * @param jsonObject the Properties object containing parameters from file
* @return SoftwareIdentity object created from the properties
*/
private SoftwareIdentity createSwidTag(JsonObject jsonObject) {
@@ -426,7 +287,7 @@ public class SwidTagGateway {
* This method creates an Entity object based on the parameters read in from
* a properties file.
*
- * @param properties the Properties object containing parameters from file
+ * @param jsonObject the Properties object containing parameters from file
* @return Entity object created from the properties
*/
private Entity createEntity(JsonObject jsonObject) {
@@ -463,7 +324,7 @@ public class SwidTagGateway {
/**
* Thsi method creates a Link element based on the parameters read in from a properties
* file.
- * @param properties the Properties object containing parameters from file
+ * @param jsonObject the Properties object containing parameters from file
* @return Link element created from the properties
*/
private Link createLink(JsonObject jsonObject) {
@@ -483,7 +344,7 @@ public class SwidTagGateway {
/**
* This method creates a Meta element based on the parameters read in from a properties
* file.
- * @param properties the Properties object containing parameters from file
+ * @param jsonObject the Properties object containing parameters from file
* @return the Meta element created from the properties
*/
private SoftwareMeta createSoftwareMeta(JsonObject jsonObject) {
@@ -514,15 +375,15 @@ public class SwidTagGateway {
/**
* This method creates a Payload from the parameters read in from a properties file.
*
- * @param properties the Properties object containing parameters from file
+ * @param jsonObject the Properties object containing parameters from file
* @return the Payload object created
*/
private ResourceCollection createPayload(JsonObject jsonObject) {
ResourceCollection payload = objectFactory.createResourceCollection();
Map attributes = payload.getOtherAttributes();
- addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARPREFIX, jsonObject.getString(SwidTagConstants.PAYLOAD_ENVVARPREFIX, ""));
- addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARSUFFIX, jsonObject.getString(SwidTagConstants.PAYLOAD_ENVVARSUFFIX, ""));
- addNonNullAttribute(attributes, SwidTagConstants._N8060_PATHSEPARATOR, jsonObject.getString(SwidTagConstants.PAYLOAD_PATHSEPARATOR, ""));
+ addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARPREFIX, jsonObject.getString(SwidTagConstants._N8060_ENVVARPREFIX.getLocalPart(), ""));
+ addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARSUFFIX, jsonObject.getString(SwidTagConstants._N8060_ENVVARSUFFIX.getLocalPart(), ""));
+ addNonNullAttribute(attributes, SwidTagConstants._N8060_PATHSEPARATOR, jsonObject.getString(SwidTagConstants._N8060_PATHSEPARATOR.getLocalPart(), ""));
return payload;
}
@@ -530,7 +391,7 @@ public class SwidTagGateway {
/**
* This method creates a Directory from the parameters read in from a properties file.
*
- * @param properties the Properties object containing parameters from file
+ * @param jsonObject the Properties object containing parameters from file
* @return Directory object created from the properties
*/
private Directory createDirectory(JsonObject jsonObject) {
@@ -540,13 +401,7 @@ public class SwidTagGateway {
addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_TYPE, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_TYPE, ""));
addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_FORMAT, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_FORMAT, ""));
addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_URI_GLOBAL, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_URI_GLOBAL, ""));
-/*
- directory.setLocation(jsonObject.getString(SwidTagConstants.DIRECTORY_LOCATION));
- String directoryRoot = jsonObject.getString(SwidTagConstants.DIRECTORY_ROOT);
- if (!directoryRoot.isEmpty()) {
- directory.setRoot(directoryRoot);
- }
-*/
+
return directory;
}
@@ -554,8 +409,7 @@ public class SwidTagGateway {
* This method creates a hirs.swid.xjc.File from three arguments, then calculates
* and stores its hash as an attribute in itself.
*
- * @param filename
- * @param location
+ * @param jsonObject
* @return hirs.swid.xjc.File object from File object
*/
private hirs.swid.xjc.File createFile(JsonObject jsonObject) {
@@ -577,32 +431,6 @@ public class SwidTagGateway {
}
}
- /**
- * This method creates a Payload from a list of Strings and a hash algorithm.
- * The Strings in the list are expected to be in the form of "[PCR_NUMBER],[PCR_VALUE]"
- * and the hash algorithm is attached as the file's xml namespace identifier.
- *
- * @param populate
- * @return
- */
- private ResourceCollection createPayload(List populate, QName hashStr) {
- ResourceCollection rc = objectFactory.createResourceCollection();
- hirs.swid.xjc.File xjcFile = null;
- String[] tempArray = null;
-
- for (String item : populate) {
- xjcFile = objectFactory.createFile();
-
- tempArray = item.split(",");
-
- xjcFile.setName(tempArray[SwidTagConstants.PCR_NUMBER]);
- xjcFile.getOtherAttributes().put(hashStr, tempArray[SwidTagConstants.PCR_VALUE]);
- rc.getDirectoryOrFileOrProcess().add(xjcFile);
- }
-
- return rc;
- }
-
/**
* This method signs a SoftwareIdentity with an xmldsig in compatibility mode.
* Current assumptions: digest method SHA256, signature method SHA256, enveloped signature
@@ -623,34 +451,47 @@ public class SwidTagGateway {
sigFactory.newSignatureMethod(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256, null),
Collections.singletonList(reference)
);
- KeyStore keystore = KeyStore.getInstance("JKS");
- keystore.load(new FileInputStream(keystoreFile), SwidTagConstants.DEFAULT_KEYSTORE_PASSWORD.toCharArray());
- KeyStore.PrivateKeyEntry privateKey = (KeyStore.PrivateKeyEntry) keystore.getEntry(SwidTagConstants.DEFAULT_PRIVATE_KEY_ALIAS,
- new KeyStore.PasswordProtection(SwidTagConstants.DEFAULT_KEYSTORE_PASSWORD.toCharArray()));
- X509Certificate certificate = (X509Certificate) privateKey.getCertificate();
+ List keyInfoElements = new ArrayList();
+
KeyInfoFactory kiFactory = sigFactory.getKeyInfoFactory();
- ArrayList
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 be75f5a0..336ea344 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
@@ -28,23 +28,35 @@ sLJl6RPCNcp+JNCXMMZiS8bmYPQnVJc1ze0I1A==
CN=example.RIM.signer,OU=PCClient,O=Example,ST=VA,C=US
- MIIDYTCCAkmgAwIBAgIJAPB+r6VBhBn4MA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAlVTMQsw
+ MIIDoTCCAomgAwIBAgIJAPB+r6VBhBn5MA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxEjAQBgNVBAMM
-CUV4YW1wbGVDQTAeFw0yMDAyMTAxODE1MzRaFw0yOTEyMTkxODE1MzRaMFwxCzAJBgNVBAYTAlVT
+CUV4YW1wbGVDQTAeFw0yMDAzMTExODExMjJaFw0zMDAxMTgxODExMjJaMFwxCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxGzAZBgNV
BAMMEmV4YW1wbGUuUklNLnNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKd1
lWGkSRuxAAY2wHag2GVxUk1dZx2PTpfQOflvLeccAVwa8mQhlsRERq+QK8ilj8Xfqs44/nBaccZD
OjdfIxIUCMfwhGXjxCaqZbgTucNsExDnu4arTGraoAwzHg0cVLiKT/Cxj9NL4dcMgxRXsPdHfXb0
923C7xYd2t2qfW05umgaj7qeQl6c68CFNsGX4JA8rWFQZvvGx5DGlK4KTcjPuQQINs5fxasNKqLY
2hq+z82x/rqwr2hmyizD6FpFSyIABPEMPfB036GEhRwu1WEMkq8yIp2jgRUoFYke9pB3ph9pVow0
-Hh4mNFSKD4pP41VSKY1nus83mdkuukPy5o0CAwEAAaMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMC
-BsAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAGuJ+dasb3/Mb7TBJ1Oe
-al5ISq8d2LQD5ke5qnjgSQWKXfQ9fcUy3dWnt3Oked/i8B/Tyk3jCdTZJU3J3iRNgTqFfMLP8rU1
-w2tPYBjjuPKiiK4YRBHPxtFxPdOL1BPmL4ZzNs33Lv6H0m4aff9p6QpMclX5b/CRjl+80JWRLiLj
-U3B0CejZB9dJrPr9SBaC31cDoeTpja9Cl86ip7KkqrZZIYeMuNF6ucWyWtjrW2kr3UhmEy8x/6y4
-KigsK8sBwmNv4N2Pu3RppeIcpjYj5NVA1hwRA4eeMgJp2u+urm3l1oo1UNX1HsSSBHp1Owc9zZLm
-07Pl8T46kpIA4sroCAU=
+Hh4mNFSKD4pP41VSKY1nus83mdkuukPy5o0CAwEAAaNvMG0wHQYDVR0OBBYEFC/euOfQMKIgnaoB
+hhqWT+3s8rzBMB8GA1UdIwQYMBaAFEahuO3bpnFf0NLneoo8XW6aw5Y4MAkGA1UdEwQCMAAwCwYD
+VR0PBAQDAgbAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQBl2Bu9xpnH
+CCeeebjx+ILQXJXBd6q5+NQlV3zzBrf0bleZRtsOmsuFvWQoKQxsfZuk7QcSvVd/1v8mqwJ0PwbF
+KQmrhIPWP+iowiBNqpG5PH9YxhpHQ1osOfibNLOXMhudIQRY0yAgqQf+MOlXYa0stX8gkgftVBDR
+utuMKyOTf4a6d8TUcbG2RnyzO/6S9bq4cPDYLqWRBM+aGN8e00UWTKpBl6/1EU8wkJA6WdllK2e8
+mVkXUPWYyHTZ0qQnrYiuLr36ycAznABDzEAoj4tMZbjIAfuscty6Ggzxl1WbyZLI6YzyXALwaYvr
+crTLeyFynlKxuCfDnr1SAHDM65BY
+ 2fdeb8e7d030a2209daa01861a964fedecf2bcc1
+
+
+ p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx
+xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9
+dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q
+otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW
+jDQeHiY0VIoPik/jVVIpjWe6zzeZ2S66Q/LmjQ==
+ AQAB
+
+