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 8b800bd7..a4f96017 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 @@ -7,12 +7,14 @@ import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.UnmarshalException; import javax.xml.crypto.dsig.keyinfo.*; +import javax.xml.parsers.DocumentBuilder; 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; @@ -42,6 +44,7 @@ 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; @@ -163,83 +166,6 @@ public class SwidTagGateway { this.pemCertificateFile = pemCertificateFile; } - /** - * default generator method that has no parameters - */ - 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 - } - } - } - } - } - /** * This method generates a base RIM from the values in a JSON file. * @@ -293,7 +219,6 @@ public class SwidTagGateway { } Document signedSoftwareIdentity = signXMLDocument(objectFactory.createSoftwareIdentity(swidTag)); - System.out.println("Signature core validity: " + validateSignedXMLDocument(signedSoftwareIdentity)); writeSwidTagFile(signedSoftwareIdentity, filename); } @@ -305,35 +230,16 @@ 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. * @@ -549,32 +455,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 @@ -717,73 +597,6 @@ public class SwidTagGateway { } } - /** - * Given an input swidtag at [path] parse any PCRs in the payload into an InputStream object. - * This method will be used in a following pull request. - * - * @param path - * @return - * @throws IOException - */ - public ByteArrayInputStream parsePayload(String path) throws IOException { - JAXBElement jaxbe = unmarshallSwidTag(path); - SoftwareIdentity softwareIdentity = (SoftwareIdentity) jaxbe.getValue(); - String pcrs = ""; - if (!softwareIdentity.getEntityOrEvidenceOrLink().isEmpty()) { - List swidtag = softwareIdentity.getEntityOrEvidenceOrLink(); - for (Object obj : swidtag) { - try { - JAXBElement element = (JAXBElement) obj; - String elementName = element.getName().getLocalPart(); - if (elementName.equals(SwidTagConstants.PAYLOAD)) { - ResourceCollection rc = (ResourceCollection) element.getValue(); - if (!rc.getDirectoryOrFileOrProcess().isEmpty()) { - pcrs = parsePCRs(rc.getDirectoryOrFileOrProcess()); - } - } - } catch (ClassCastException e) { - System.out.println("Found a non-JAXBElement object!" + e.getMessage()); - throw new IOException("Found an invalid element in the swidtag file!"); - } - } - } - return new ByteArrayInputStream(pcrs.getBytes(StandardCharsets.UTF_8)); - } - - /** - * This method traverses a hirs.swid.xjc.Directory recursively until it finds at - * least one hirs.swid.xjc.File. This File is expected to have an attribute of the form - * "[hash algorithm]=[hash value]." - * - * @param list of swidtag elements - * @return the hash value(s) parsed from the File object(s) - */ - private String parsePCRs(List list) { - final String newline = System.lineSeparator(); - StringBuilder sb = new StringBuilder(); - for (Object listItem : list) { - if (listItem instanceof Directory) { - Directory dir = (Directory) listItem; - if (!dir.getDirectoryOrFile().isEmpty()) { - parsePCRs(dir.getDirectoryOrFile()); - } - } else if (listItem instanceof hirs.swid.xjc.File){ - hirs.swid.xjc.File pcr = (hirs.swid.xjc.File) listItem; - String pcrHash = ""; - if (!pcr.getOtherAttributes().isEmpty()) { - Object[] fileAttributes = pcr.getOtherAttributes().values().toArray(); - pcrHash = (String) fileAttributes[0]; - } - if (pcrHash.isEmpty()) { - pcrHash = "null"; - } - sb.append(pcr.getName() + "," + pcrHash); - } - } - System.out.println(sb.toString()); - return sb.toString(); - } - /** * This method unmarshalls the swidtag found at [path] into a JAXBElement object * and validates it according to the schema. @@ -792,18 +605,19 @@ public class SwidTagGateway { * @return the SoftwareIdentity element at the root of the swidtag * @throws IOException if the swidtag cannot be unmarshalled or validated */ - private JAXBElement unmarshallSwidTag(String path) throws IOException { - File input = null; - InputStream is = null; - JAXBElement swidtag = null; - try { - input = new File(path); - is = SwidTagGateway.class.getClassLoader().getResourceAsStream(SwidTagConstants.SCHEMA_URL); - SchemaFactory schemaFactory = SchemaFactory.newInstance(SwidTagConstants.SCHEMA_LANGUAGE); - Schema schema = schemaFactory.newSchema(new StreamSource(is)); - unmarshaller.setSchema(schema); - swidtag = (JAXBElement) unmarshaller.unmarshal(input); - } catch (SAXException e) { + private Document unmarshallSwidTag(String path) { + InputStream is = null; + Document document = null; + try { + document = removeXMLWhitespace(path); + is = SwidTagGateway.class.getClassLoader().getResourceAsStream(SwidTagConstants.SCHEMA_URL); + SchemaFactory schemaFactory = SchemaFactory.newInstance(SwidTagConstants.SCHEMA_LANGUAGE); + Schema schema = schemaFactory.newSchema(new StreamSource(is)); + unmarshaller.setSchema(schema); + unmarshaller.unmarshal(document); + } catch (IOException e) { + System.out.println(e.getMessage()); + } catch (SAXException e) { System.out.println("Error setting schema for validation!"); } catch (UnmarshalException e) { System.out.println("Error validating swidtag file!"); @@ -812,18 +626,46 @@ public class SwidTagGateway { } catch (JAXBException e) { e.printStackTrace(); } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - System.out.println("Error closing input stream"); - } - } - if (swidtag != null) { - return swidtag; - } else { - throw new IOException("Invalid swidtag file!"); - } + if (is != null) { + try { + is.close(); + } catch (IOException e) { + System.out.println("Error closing input stream"); + } + } } + + return document; + } + + /** + * This method strips all whitespace from an xml file, including indents and spaces + * added for human-readability. + * @param path + * @return + */ + private Document removeXMLWhitespace(String path) throws IOException { + TransformerFactory tf = TransformerFactory.newInstance(); + Source source = new StreamSource(new File("identity_transform.xslt")); + Document document = null; + File input = new File(path); + if (input.length() > 0) { + try { + Transformer transformer = tf.newTransformer(source); + DOMResult result = new DOMResult(); + transformer.transform(new StreamSource(input), result); + document = (Document) result.getNode(); + } catch (TransformerConfigurationException e) { + System.out.println("Error configuring transformer!"); + e.printStackTrace(); + } catch (TransformerException e) { + System.out.println("Error transforming input!"); + e.printStackTrace(); + } + } else { + throw new IOException("Input file is empty!"); + } + + return document; } } 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 551e3769..da380b03 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 @@ -16,7 +16,7 @@ public class Commander { @Parameter(names = {"-h", "--help"}, help = true, description = "Print this help text.") private boolean help; - @Parameter(names = {"-c", "--create \"base|eventlog|pcr\""}, order = 0, + @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" @Parameter(names = {"-a", "--attributes "}, order = 1, @@ -35,6 +35,7 @@ public class Commander { 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.") private String publicCertificate = ""; +/* @Parameter(names = {"-l", "--rimel "}, order = 6, description = "The TCG eventlog file to use as a support RIM. By default the last system eventlog will be used.") private String rimEventLog = ""; @@ -47,7 +48,7 @@ public class Commander { description = "The signature data in will be combined with the data in " + "and written to , or will overwrite if is not given.") private String signatureData = ""; - +*/ public boolean isHelp() { return help; } @@ -75,7 +76,7 @@ public class Commander { public String getPublicCertificate() { return publicCertificate; } - +/* public String getRimEventLog() { return rimEventLog; } @@ -91,7 +92,7 @@ public class Commander { public String getSignatureData() { return signatureData; } - +*/ public String printHelpExamples() { StringBuilder sb = new StringBuilder(); sb.append("Create a base RIM using the values in attributes.json; " + @@ -112,11 +113,12 @@ public class Commander { sb.append("Verify file: " + getVerifyFile() + System.lineSeparator()); sb.append("Private key file: " + getPrivateKeyFile() + System.lineSeparator()); sb.append("Public certificate: " + getPublicCertificate() + System.lineSeparator()); +/* sb.append("Event log support RIM: " + 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 bee91cf2..62373aba 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 @@ -14,17 +14,16 @@ import org.testng.annotations.Test; public class TestSwidTagGateway { private SwidTagGateway gateway; - private String inputFile, outputFile, hashType; private final String DEFAULT_OUTPUT = "generated_swidTag.swidtag"; private final String DEFAULT_WITH_CERT = "generated_with_cert.swidtag"; private final String DEFAULT_NO_CERT = "generated_no_cert.swidtag"; + private final String certificateFile = "RimSignCert.pem"; + private final String privateKeyFile = "privateRimKey.pem"; private InputStream expectedFile; @BeforeClass public void setUp() throws Exception { gateway = new SwidTagGateway(); - inputFile = TestSwidTagGateway.class.getClassLoader().getResource("examplecsv.csv").getFile(); - hashType = "SHA256"; } @AfterClass @@ -35,23 +34,28 @@ public class TestSwidTagGateway { } /** - * Creating a base RIM with default attributes with an X509Certificate element. + * This test corresponds to the arguments: + * -c base -k privateRimKey.pem -p RimSignCert.pem */ @Test - public void testGenerateDefaultWithCert() { - gateway.setShowCert(true); - gateway.generateSwidTag(); + public void testCreateBaseWithCert() { + gateway.setDefaultCredentials(false); + gateway.setPemCertificateFile(certificateFile); + gateway.setPemPrivateKeyFile(privateKeyFile); + gateway.generateSwidTag(DEFAULT_OUTPUT); expectedFile = (InputStream) TestSwidTagGateway.class.getClassLoader().getResourceAsStream(DEFAULT_WITH_CERT); Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT)); } /** - * Create a base RIM with default attributes without an X509Certificate element. + * This test corresponds to the arguments: + * -c base + * -c base -a attributes.json */ @Test - public void testGenerateDefaultNoCert() { - gateway.setShowCert(false); - gateway.generateSwidTag(); + public void testCreateBaseWithoutCert() { + gateway.setDefaultCredentials(true); + gateway.generateSwidTag(DEFAULT_OUTPUT); expectedFile = (InputStream) TestSwidTagGateway.class.getClassLoader().getResourceAsStream(DEFAULT_NO_CERT); Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT)); } @@ -68,35 +72,6 @@ public class TestSwidTagGateway { } } - /** - * Verify expected values of a File element in a Payload element. - */ - @Test - public void testParsePayload() { - InputStream is = null; - outputFile = TestSwidTagGateway.class.getClassLoader().getResource(DEFAULT_WITH_CERT).getPath(); - try { - is = gateway.parsePayload(outputFile); - Scanner scanner = new Scanner(is, "UTF-8"); - String test = "Example.com.iotBase.bin,688e293e3ccb522f6cf8a027c9ade7960f84bd0bf3a0b99812bc1fa498a2db8d"; - String temp = ""; - while (scanner.hasNext()) { - temp = scanner.next(); - Assert.assertEquals(temp, test, "temp: " + temp + ", test: " + test); - } - } catch (IOException e) { - Assert.fail("Error parsing test file!"); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - Assert.fail("Failed to close input stream!"); - } - } - } - } - /** * This method compares two files by bytes to determine if they are the same or not. * @param file to be compared to the expected value. 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 6269de6b..719497c2 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 @@ -26,9 +26,17 @@ zu3HTmQfeRYs/c6Ck1k3bL1jnyWoNzhBqCuPYrZtPbv9opVP0YOxM5IjRkRgkZIDgYbh1k4WXw8O /iIMZuVJDfKQJSNCTAZsIbUatGDQc/nOihLHdI90wG8zu9amgrl1AEKzH8z864Fan5uuXolfAaak sLJl6RPCNcp+JNCXMMZiS8bmYPQnVJc1ze0I1A== - - CN=example.RIM.signer,OU=PCClient,O=Example,ST=VA,C=US - + #2fdeb8e7d030a2209daa01861a964fedecf2bcc1 + + + p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx +xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9 +dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q +otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW +jDQeHiY0VIoPik/jVVIpjWe6zzeZ2S66Q/LmjQ== + AQAB + + 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..7ef73d70 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 + +