Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ This will help prevent future XML signature wrapping attacks.
- RSA-SHA256 <http://www.w3.org/2001/04/xmldsig-more#rsa-sha256>
- RSA-SHA256 with MGF1 <http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1>
- RSA-SHA512 <http://www.w3.org/2001/04/xmldsig-more#rsa-sha512>
- ECDSA-SHA256 <http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256>
- ECDSA-SHA512 <http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512>

HMAC-SHA1 is also available but it is disabled by default

Expand Down
16 changes: 12 additions & 4 deletions example/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ const dom = require("@xmldom/xmldom").DOMParser;
const SignedXml = require("xml-crypto").SignedXml;
const fs = require("fs");

function signXml(xml, xpath, key, dest) {
function signXml(xml, xpath, key, dest, cert) {
const sig = new SignedXml();
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#"
sig.signatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
sig.privateKey = fs.readFileSync(key);
sig.addReference(xpath);
sig.publicCert = fs.readFileSync(cert); // To populate KeyInfo, as an example
sig.addReference({
xpath,
digestAlgorithm: "http://www.w3.org/2001/04/xmlenc#sha256",
transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.computeSignature(xml);
fs.writeFileSync(dest, sig.getSignedXml());
}
Expand All @@ -20,7 +27,8 @@ function validateXml(xml, key) {
doc,
)[0];
const sig = new SignedXml();
sig.publicCert = key;
sig.publicCert = fs.readFileSync(key); // Note since the XML has a KeyInfo, this cert is NOT doing anything!
// Validate the cert in `KeyInfo` on your own if that is your security model. See: <https://github.com/node-saml/xml-crypto/discussions/399>
sig.loadSignature(signature.toString());
const res = sig.checkSignature(xml);
if (!res) {
Expand All @@ -32,7 +40,7 @@ function validateXml(xml, key) {
const xml = "<library>" + "<book>" + "<name>Harry Potter</name>" + "</book>" + "</library>";

//sign an xml document
signXml(xml, "//*[local-name(.)='book']", "client.pem", "result.xml");
signXml(xml, "//*[local-name(.)='book']", "client.pem", "result.xml", "client_public.pem");

console.log("xml signed successfully");

Expand Down
56 changes: 56 additions & 0 deletions example/local_example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* eslint-disable no-console */
// Run with `npm run example`, requires one-time `npm run build` to generate `/lib` code (and re-run if you update `/src`)

const select = require("xpath").select
const dom = require("@xmldom/xmldom").DOMParser;
const SignedXml = require("../").SignedXml;
const fs = require("fs");
Comment on lines +4 to +7
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use package name import instead of relative path.

The import on line 6 uses a relative path (require("../")) rather than the package name. Example files should use require("xml-crypto") to demonstrate usage from an end-user's perspective, matching the pattern in example/example.js.

📦 Proposed fix
 const select = require("xpath").select
 const dom = require("@xmldom/xmldom").DOMParser;
-const SignedXml = require("../").SignedXml;
+const SignedXml = require("xml-crypto").SignedXml;
 const fs = require("fs");

Based on learnings: "Example files in the node-saml/xml-crypto repository should use require("xml-crypto") (the package name) rather than relative paths to build artifacts, since they demonstrate usage from an end-user's perspective."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const select = require("xpath").select
const dom = require("@xmldom/xmldom").DOMParser;
const SignedXml = require("../").SignedXml;
const fs = require("fs");
const select = require("xpath").select
const dom = require("@xmldom/xmldom").DOMParser;
const SignedXml = require("xml-crypto").SignedXml;
const fs = require("fs");
🤖 Prompt for AI Agents
In `@example/local_example.js` around lines 4 - 7, Replace the relative
require("../") that imports SignedXml with the package name
require("xml-crypto") so the example demonstrates end-user usage; locate the
SignedXml import in local_example.js (currently assigned to the SignedXml
variable) and update that require to "xml-crypto" while leaving other requires
(select, DOMParser, fs) unchanged.


function signXml(xml, xpath, key, dest, cert) {
const sig = new SignedXml();
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#"
sig.signatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
sig.privateKey = fs.readFileSync(__dirname + "/" + key);
sig.publicCert = fs.readFileSync(__dirname + "/" + cert); // To populate KeyInfo, as an example
sig.addReference({
xpath,
digestAlgorithm: "http://www.w3.org/2001/04/xmlenc#sha256",
transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.computeSignature(xml);
fs.writeFileSync(__dirname + "/" + dest, sig.getSignedXml());
}

function validateXml(xml, key) {
const doc = new dom().parseFromString(xml);
const signature = select(
"/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
doc,
)[0];
const sig = new SignedXml();
sig.publicCert = fs.readFileSync(__dirname + "/" + key); // Note since the XML has a KeyInfo, this cert is NOT doing anything!
// Validate the cert in `KeyInfo` on your own if that is your security model. See: <https://github.com/node-saml/xml-crypto/discussions/399>
sig.loadSignature(signature.toString());
const res = sig.checkSignature(xml);
if (!res) {
console.log(sig.validationErrors);
}
return res;
}

const xml = "<library>" + "<book>" + "<name>Harry Potter</name>" + "</book>" + "</library>";

//sign an xml document
signXml(xml, "//*[local-name(.)='book']", "client.pem", "result.xml", "client_public.pem");

console.log("xml signed successfully");

const signedXml = fs.readFileSync(__dirname + "/" + "result.xml").toString();
console.log("validating signature...");

//validate an xml document
if (validateXml(signedXml, "client_public.pem")) {
console.log("signature is valid");
} else {
console.log("signature not valid");
}
1 change: 1 addition & 0 deletions example/result.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<library><book Id="_0"><name>Harry Potter</name></book><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><Reference URI="#_0"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>9d/ciWlVZkaJnJ3KBB5WY1H2Y8WRXPB2DquM0goT8jY=</DigestValue></Reference></SignedInfo><SignatureValue>uxmxGw2O3B6ylkhEXOaZd1Iupgy3sHtCoBTgbmSMSnHYOitiHXRdHjJGJdMG4EMSgItsB6k5gxrKeyQ/5LkwvMqSc0VRPXd9vavt0pYatqwWDO/r6WITLb0jzymJfNDJ4lr4OcqH4zBKX8Deb6EpS9L7S6OXNqd1vOZ0STMSSaM=</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIBxDCCAW6gAwIBAgIQxUSXFzWJYYtOZnmmuOMKkjANBgkqhkiG9w0BAQQFADAWMRQwEgYDVQQDEwtSb290IEFnZW5jeTAeFw0wMzA3MDgxODQ3NTlaFw0zOTEyMzEyMzU5NTlaMB8xHTAbBgNVBAMTFFdTRTJRdWlja1N0YXJ0Q2xpZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+L6aB9x928noY4+0QBsXnxkQE4quJl7c3PUPdVu7k9A02hRG481XIfWhrDY5i7OEB7KGW7qFJotLLeMec/UkKUwCgv3VvJrs2nE9xO3SSWIdNzADukYh+Cxt+FUU6tUkDeqg7dqwivOXhuOTRyOI3HqbWTbumaLdc8jufz2LhaQIDAQABo0swSTBHBgNVHQEEQDA+gBAS5AktBh0dTwCNYSHcFmRjoRgwFjEUMBIGA1UEAxMLUm9vdCBBZ2VuY3mCEAY3bACqAGSKEc+41KpcNfQwDQYJKoZIhvcNAQEEBQADQQAfIbnMPVYkNNfX1tG1F+qfLhHwJdfDUZuPyRPucWF5qkh6sSdWVBY5sT/txBnVJGziyO8DPYdu2fPMER8ajJfl</X509Certificate></X509Data></KeyInfo></Signature></library>
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"prettier-format": "prettier --config .prettierrc.json --write .",
"prerelease": "git clean -xfd && npm ci && npm test",
"release": "release-it",
"test": "nyc mocha"
"test": "nyc mocha",
"example": "node ./example/local_example.js"
},
"dependencies": {
"@xmldom/is-dom-node": "^1.0.1",
Expand Down
60 changes: 60 additions & 0 deletions src/signature-algorithms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,36 @@ export class RsaSha256 implements SignatureAlgorithm {
};
}

export class EcdsaSha256 implements SignatureAlgorithm {
getSignature = createOptionalCallbackFunction(
(signedInfo: crypto.BinaryLike, privateKey: crypto.KeyLike): string => {
// Maybe the fix for ts-ignore below?
// const parsedPrivateKey = crypto.createPrivateKey(privateKey);
const signer = crypto.createSign("SHA256");
signer.update(signedInfo);
// @ts-ignore
const res = signer.sign({ key: privateKey, dsaEncoding: 'ieee-p1363' }, "base64");

return res;
},
);

verifySignature = createOptionalCallbackFunction(
(material: string, key: crypto.KeyLike, signatureValue: string): boolean => {
const publicKey = crypto.createPublicKey(key);
const verifier = crypto.createVerify("SHA256");
verifier.update(material);
const res = verifier.verify({ key: publicKey, dsaEncoding: 'ieee-p1363' }, signatureValue, "base64");

return res;
},
);

getAlgorithmName = () => {
return "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256";
};
}

export class RsaSha256Mgf1 implements SignatureAlgorithm {
getSignature = createOptionalCallbackFunction(
(signedInfo: crypto.BinaryLike, privateKey: crypto.KeyLike): string => {
Expand Down Expand Up @@ -126,6 +156,36 @@ export class RsaSha512 implements SignatureAlgorithm {
};
}

export class EcdsaSha512 implements SignatureAlgorithm {
getSignature = createOptionalCallbackFunction(
(signedInfo: crypto.BinaryLike, privateKey: crypto.KeyLike): string => {
// Maybe the fix for ts-ignore below?
// const parsedPrivateKey = crypto.createPrivateKey(privateKey);
const signer = crypto.createSign("SHA512");
signer.update(signedInfo);
// @ts-ignore
const res = signer.sign({ key: privateKey, dsaEncoding: 'ieee-p1363' }, "base64");

return res;
},
);

verifySignature = createOptionalCallbackFunction(
(material: string, key: crypto.KeyLike, signatureValue: string): boolean => {
const publicKey = crypto.createPublicKey(key);
const verifier = crypto.createVerify("SHA512");
verifier.update(material);
const res = verifier.verify({ key: publicKey, dsaEncoding: 'ieee-p1363' }, signatureValue, "base64");

return res;
},
);

getAlgorithmName = () => {
return "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512";
};
}

export class HmacSha1 implements SignatureAlgorithm {
getSignature = createOptionalCallbackFunction(
(signedInfo: crypto.BinaryLike, privateKey: crypto.KeyLike): string => {
Expand Down
2 changes: 2 additions & 0 deletions src/signed-xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,10 @@ export class SignedXml {
SignatureAlgorithms: Record<SignatureAlgorithmType, new () => SignatureAlgorithm> = {
"http://www.w3.org/2000/09/xmldsig#rsa-sha1": signatureAlgorithms.RsaSha1,
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256": signatureAlgorithms.RsaSha256,
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256": signatureAlgorithms.EcdsaSha256,
"http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1": signatureAlgorithms.RsaSha256Mgf1,
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512": signatureAlgorithms.RsaSha512,
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512": signatureAlgorithms.EcdsaSha512,
// Disabled by default due to key confusion concerns.
// 'http://www.w3.org/2000/09/xmldsig#hmac-sha1': SignatureAlgorithms.HmacSha1
};
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ export type HashAlgorithmType =
export type SignatureAlgorithmType =
| "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
| "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
| "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"
| "http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1"
| "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
| "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"
| "http://www.w3.org/2000/09/xmldsig#hmac-sha1"
| string;

Expand Down
92 changes: 92 additions & 0 deletions test/signature-unit-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const signatureAlgorithms = [
"http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
];
const ecdsaSignatureAlgorithms = [
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
];

describe("Signature unit tests", function () {
describe("sign and verify", function () {
Expand Down Expand Up @@ -75,6 +79,67 @@ describe("Signature unit tests", function () {
});
});

describe("sign and verify - ecdsa", function () {
ecdsaSignatureAlgorithms.forEach((signatureAlgorithm) => {
function signWith(signatureAlgorithm: string): string {
const xml = '<root><x attr="value"></x></root>';
const sig = new SignedXml();
sig.privateKey = fs.readFileSync("./test/static/client_ecdsa.pem");

sig.addReference({
xpath: "//*[local-name(.)='x']",
digestAlgorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});

sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.signatureAlgorithm = signatureAlgorithm;
sig.computeSignature(xml);
return sig.getSignedXml();
}

function loadSignature(xml: string): SignedXml {
const doc = new xmldom.DOMParser().parseFromString(xml);
const node = xpath.select1(
"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
doc,
);
isDomNode.assertIsNodeLike(node);
const sig = new SignedXml();
sig.publicCert = fs.readFileSync("./test/static/client_public_ecdsa.pem");
sig.loadSignature(node);
return sig;
}

it(`should verify signed xml with ${signatureAlgorithm}`, function () {
const xml = signWith(signatureAlgorithm);
const sig = loadSignature(xml);
const res = sig.checkSignature(xml);
expect(
res,
`expected all signatures with ${signatureAlgorithm} to be valid, but some reported invalid`,
).to.be.true;
});

it(`should fail verification of signed xml with ${signatureAlgorithm} after manipulation`, function () {
const xml = signWith(signatureAlgorithm);
const doc = new xmldom.DOMParser().parseFromString(xml);
const node = xpath.select1("//*[local-name(.)='x']", doc);
isDomNode.assertIsElementNode(node);
const targetElement = node as Element;
targetElement.setAttribute("attr", "manipulatedValue");
const manipulatedXml = new xmldom.XMLSerializer().serializeToString(doc);

const sig = loadSignature(manipulatedXml);
const res = sig.checkSignature(manipulatedXml);
expect(
res,
`expected all signatures with ${signatureAlgorithm} to be invalid, but some reported valid`,
).to.be.false;
});
});
});

describe("verify adds ID", function () {
function nodeExists(doc, xpathArg) {
if (!doc && !xpathArg) {
Expand Down Expand Up @@ -943,6 +1008,20 @@ describe("Signature unit tests", function () {
return sig;
}

function loadEcdsaSignature(xml: string) {
const doc = new xmldom.DOMParser().parseFromString(xml);
const node = xpath.select1(
"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
doc,
);
isDomNode.assertIsNodeLike(node);
const sig = new SignedXml();
sig.publicCert = fs.readFileSync("./test/static/ecdsa_external.pem");
sig.loadSignature(node);

return sig;
}

function passValidSignature(file: string, mode?: "wssecurity") {
const xml = fs.readFileSync(file, "utf8");
const sig = loadSignature(xml, mode);
Expand All @@ -952,6 +1031,15 @@ describe("Signature unit tests", function () {
expect(sig.getSignedReferences().length).to.equal(sig.getReferences().length);
}

function passValidEcdsaSignature(file: string) {
const xml = fs.readFileSync(file, "utf8");
const sig = loadEcdsaSignature(xml);
const res = sig.checkSignature(xml);
expect(res, "expected all signatures to be valid, but some reported invalid").to.be.true;
/* eslint-disable-next-line deprecation/deprecation */
expect(sig.getSignedReferences().length).to.equal(sig.getReferences().length);
}

function failInvalidSignature(file: string, idMode?: "wssecurity") {
const xml = fs.readFileSync(file).toString();
const sig = loadSignature(xml, idMode);
Expand All @@ -973,6 +1061,10 @@ describe("Signature unit tests", function () {
it("verifies valid signature", function () {
passValidSignature("./test/static/valid_signature.xml");
});

it("verifies valid ecdsa signature", function () {
passValidEcdsaSignature("./test/static/valid_signature_ecdsa.xml");
});

it("verifies valid signature with lowercase id attribute", function () {
passValidSignature("./test/static/valid_signature_with_lowercase_id_attribute.xml");
Expand Down
5 changes: 5 additions & 0 deletions test/static/client_ecdsa.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOg1FiE/iu8uoRXX3UvBs53JIEsjkcf9IbMpJsfkvG30oAoGCCqGSM49
AwEHoUQDQgAE69ImJGeiClnYW20zXK3L+w5q463+PN302fpmEDE/6xTEbG/KIxcA
d77nrzo5Iq4ve2SqL0Bk1Yxk2V/1f8t52g==
-----END EC PRIVATE KEY-----
13 changes: 13 additions & 0 deletions test/static/client_public_ecdsa.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB3zCCAYWgAwIBAgIUYjTFVRq9oJ9JsEdzs9GEp+Ro2nYwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNjAxMjcyMDA0MjhaFw0yNzAxMjIy
MDA0MjhaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAATr0iYkZ6IKWdhbbTNcrcv7Dmrjrf483fTZ+mYQMT/rFMRsb8ojFwB3
vuevOjkiri97ZKovQGTVjGTZX/V/y3nao1MwUTAdBgNVHQ4EFgQUKdQQ4ogzLU06
Gypz35quxaLJr50wHwYDVR0jBBgwFoAUKdQQ4ogzLU06Gypz35quxaLJr50wDwYD
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiADI3VXNdnYMIIFlVLS6Ss2
E+tamOigyNvruaKT+0YiGQIhALYU9Dyu2fRRvULX7sBpv7Dxk/4ynUCcCTJ1L9SK
O9bJ
-----END CERTIFICATE-----
8 changes: 8 additions & 0 deletions test/static/ecdsa_external.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE-----
MIIBEDCBuKADAgECAggVM8YfT8EdfTAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDEwR0
ZXN0MB4XDTIxMDczMDA3NTU1NVoXDTIxMDczMDA3NTU1NVowDzENMAsGA1UEAxME
dGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHpb/uly4GB+9G2BKgToi57/
XzqapEdo2Pys48RMtj8tc6WE2BO0TJoR1KJZ1Bu05OQ0aOwyFGo1QY65V6sgONIw
CgYIKoZIzj0EAwIDRwAwRAIgV50ULGELC8aTSxOmTPptqHjOgKlbKLlQ+CuErOUB
CucCIBvn/IWSLPVqwoQNzP7VnRgk9mZvUuTW0MaIf/4lhOc7
-----END CERTIFICATE-----
1 change: 1 addition & 0 deletions test/static/valid_signature_ecdsa.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<message><content>Just remember ALL CAPS when you spell the man name</content><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>9A4u9FDDvQS0fcqS76EbS5Ir95wh3JOu2QldyyfWrHs=</DigestValue></Reference></SignedInfo><SignatureValue>A1Vz+93PgSq3auxwqW087exDtOYgSazYTSgYlXZgWVZI6tKXwrZZ9O4SdQiHHI4Y2Ro8Ho5zgf+HjpN/ushvPw==</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIBEDCBuKADAgECAggVM8YfT8EdfTAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDEwR0ZXN0MB4XDTIxMDczMDA3NTU1NVoXDTIxMDczMDA3NTU1NVowDzENMAsGA1UEAxMEdGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHpb/uly4GB+9G2BKgToi57/XzqapEdo2Pys48RMtj8tc6WE2BO0TJoR1KJZ1Bu05OQ0aOwyFGo1QY65V6sgONIwCgYIKoZIzj0EAwIDRwAwRAIgV50ULGELC8aTSxOmTPptqHjOgKlbKLlQ+CuErOUBCucCIBvn/IWSLPVqwoQNzP7VnRgk9mZvUuTW0MaIf/4lhOc7</X509Certificate></X509Data></KeyInfo></Signature></message>