Implement -v in JCommander. Clean up unit tests.

This commit is contained in:
chubtub 2020-03-17 17:05:19 -04:00
parent 0123a081a8
commit 0c57e58c46
5 changed files with 117 additions and 278 deletions

View File

@ -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<String> 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> entity = objectFactory.createSoftwareIdentityEntity(createEntity(new JsonObject()));
swidTag.getEntityOrEvidenceOrLink().add(entity);
// we should have resources, there for we need a collection
JAXBElement<ResourceCollection> resources = objectFactory.createSoftwareIdentityPayload(createPayload(tempList, hashValue));
swidTag.getEntityOrEvidenceOrLink().add(resources);
JAXBElement<SoftwareIdentity> 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<SoftwareIdentity> 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<String> 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<Object> 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;
}
}

View File

@ -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 <path>"}, 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 <path>"}, 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 <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;
}
@ -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();
}
}

View File

@ -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.

View File

@ -26,9 +26,17 @@ zu3HTmQfeRYs/c6Ck1k3bL1jnyWoNzhBqCuPYrZtPbv9opVP0YOxM5IjRkRgkZIDgYbh1k4WXw8O
/iIMZuVJDfKQJSNCTAZsIbUatGDQc/nOihLHdI90wG8zu9amgrl1AEKzH8z864Fan5uuXolfAaak
sLJl6RPCNcp+JNCXMMZiS8bmYPQnVJc1ze0I1A==</SignatureValue>
<KeyInfo>
<X509Data>
<X509SubjectName>CN=example.RIM.signer,OU=PCClient,O=Example,ST=VA,C=US</X509SubjectName>
</X509Data>
<KeyName>#2fdeb8e7d030a2209daa01861a964fedecf2bcc1</KeyName>
<KeyValue>
<RSAKeyValue>
<Modulus>p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx
xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9
dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q
otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW
jDQeHiY0VIoPik/jVVIpjWe6zzeZ2S66Q/LmjQ==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</SoftwareIdentity>

View File

@ -28,23 +28,35 @@ sLJl6RPCNcp+JNCXMMZiS8bmYPQnVJc1ze0I1A==</SignatureValue>
<KeyInfo>
<X509Data>
<X509SubjectName>CN=example.RIM.signer,OU=PCClient,O=Example,ST=VA,C=US</X509SubjectName>
<X509Certificate>MIIDYTCCAkmgAwIBAgIJAPB+r6VBhBn4MA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAlVTMQsw
<X509Certificate>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=</X509Certificate>
Hh4mNFSKD4pP41VSKY1nus83mdkuukPy5o0CAwEAAaNvMG0wHQYDVR0OBBYEFC/euOfQMKIgnaoB
hhqWT+3s8rzBMB8GA1UdIwQYMBaAFEahuO3bpnFf0NLneoo8XW6aw5Y4MAkGA1UdEwQCMAAwCwYD
VR0PBAQDAgbAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQBl2Bu9xpnH
CCeeebjx+ILQXJXBd6q5+NQlV3zzBrf0bleZRtsOmsuFvWQoKQxsfZuk7QcSvVd/1v8mqwJ0PwbF
KQmrhIPWP+iowiBNqpG5PH9YxhpHQ1osOfibNLOXMhudIQRY0yAgqQf+MOlXYa0stX8gkgftVBDR
utuMKyOTf4a6d8TUcbG2RnyzO/6S9bq4cPDYLqWRBM+aGN8e00UWTKpBl6/1EU8wkJA6WdllK2e8
mVkXUPWYyHTZ0qQnrYiuLr36ycAznABDzEAoj4tMZbjIAfuscty6Ggzxl1WbyZLI6YzyXALwaYvr
crTLeyFynlKxuCfDnr1SAHDM65BY</X509Certificate>
</X509Data>
<KeyName>#2fdeb8e7d030a2209daa01861a964fedecf2bcc1</KeyName>
<KeyValue>
<RSAKeyValue>
<Modulus>p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx
xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9
dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q
otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW
jDQeHiY0VIoPik/jVVIpjWe6zzeZ2S66Q/LmjQ==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</SoftwareIdentity>