### Install xmldom Parser Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Install the `xmldom` package, which is used in the examples for parsing XML documents. ```shell npm install @xmldom/xmldom ``` -------------------------------- ### Signed XML with KeyInfo Element Source: https://github.com/node-saml/xml-crypto/blob/master/README.md This example shows the structure of a signature that includes a KeyInfo element containing an X509Certificate, which is generated when the publicCert and getKeyInfoContent properties are set. ```xml ...[signature info removed]... vhWzpQyIYuncHUZV9W...[long base64 removed]... MIIGYjCCBJagACCBN...[long base64 removed]... ``` -------------------------------- ### Generated Signed XML Structure Source: https://github.com/node-saml/xml-crypto/blob/master/README.md This is an example of the XML document after being signed. It includes the original content and the added signature block. ```xml Harry Potter cdiS43aFDQMnb3X8yaIUej3+z9Q= vhWzpQyIYuncHUZV9W...[long base64 removed]... ``` -------------------------------- ### Run Project Tests Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Execute the project's test suite using npm. This command utilizes Mocha and Chai for testing. ```shell npm test ``` -------------------------------- ### Customize SignedXml Constructor Options Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Pass options to the `SignedXml` constructor to customize the verification process. `publicCert` is used for verification, and `getCertFromKeyInfo` can be customized to extract the certificate from the KeyInfo element. ```javascript new SignedXml({ publicCert: client_public_pem, getCertFromKeyInfo: () => null, }); ``` -------------------------------- ### Import Modules for XML Signing Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Import necessary modules from the xml-crypto library and the file system for signing operations. ```javascript var SignedXml = require("xml-crypto").SignedXml, fs = require("fs"); ``` -------------------------------- ### Implement Custom Canonicalization Algorithm Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Implement a custom canonicalization algorithm, similar to a transformation, but applied to SignedInfo. The process method should return the canonical string representation of the node. ```javascript function MyCanonicalization() { /*given a node (from the xmldom module) return its canonical representation (as string)*/ this.process = function (node) { //you should apply your transformation before returning return "< x/>"; }; this.getAlgorithmName = function () { return "http://myCanonicalization"; }; } ``` -------------------------------- ### Sign XML with Custom Algorithms Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Configure and compute the signature for an XML document using custom algorithms for signature, canonicalization, transformation, and digest. Ensure private key and certificate are loaded. ```javascript function signXml(xml, xpath, key, dest) { var options = { publicCert: fs.readFileSync("my_public_cert.pem", "latin1"), privateKey: fs.readFileSync(key), /*configure the signature object to use the custom algorithms*/ signatureAlgorithm: "http://mySignatureAlgorithm", canonicalizationAlgorithm: "http://MyCanonicalization", }; var sig = new SignedXml(options); sig.addReference({ xpath: "//*[local-name(.)='x']", transforms: ["http://MyTransformation"], digestAlgorithm: "http://myDigestAlgorithm", }); sig.addReference({ xpath, transforms: ["http://MyTransformation"], digestAlgorithm: "http://myDigestAlgorithm", }); sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#"; sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; sig.computeSignature(xml); fs.writeFileSync(dest, sig.getSignedXml()); } var xml = "" + "" + "Harry Potter" + ""; (""); signXml(xml, "//*[local-name(.)='book']", "client.pem", "result.xml"); ``` -------------------------------- ### SignedXml Constructor Source: https://github.com/node-saml/xml-crypto/blob/master/README.md The SignedXml constructor initializes an object for signing and verifying XML documents. It accepts an optional options object to configure its behavior. ```APIDOC ## SignedXml Constructor ### Description Initializes a SignedXml object for signing and verifying XML documents. ### Parameters #### Options - **idMode** (string) - Optional - Default `null`. If 'wssecurity', creates/validates IDs with the ws-security namespace. - **idAttribute** (string) - Optional - Default `Id`, `ID`, or `id`. The name of the attribute containing the element's ID. - **privateKey** (string or Buffer) - Optional - Default `null`. The private key for signing. - **publicCert** (string or Buffer) - Optional - Default `null`. The public certificate for verification. - **signatureAlgorithm** (string) - Optional. The signature algorithm to use. - **canonicalizationAlgorithm** (string) - Optional - Default `undefined`. The canonicalization algorithm to use. - **inclusiveNamespacesPrefixList** (string) - Optional - Default `null`. A list of namespace prefixes to include during canonicalization. - **implicitTransforms** (string[]) - Optional - Default `[]`. A list of implicit transforms for verification. - **keyInfoAttributes** (object) - Optional - Default `{}`. Attributes to add to the KeyInfo node. - **getKeyInfoContent** (function) - Optional - Default `SignedXml.getKeyInfoContent`. Function to get KeyInfo node content. - **getCertFromKeyInfo** (function) - Optional - Default `noop`. Function to get certificate from KeyInfo node. ``` -------------------------------- ### Verify XML Signature Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Load an XML document, parse it, select the signature element, and use `SignedXml` to verify the signature against the provided XML. Ensure the `publicCert` is loaded from a file. ```javascript var select = require("xml-crypto").xpath, dom = require("@xmldom/xmldom").DOMParser, SignedXml = require("xml-crypto").SignedXml, fs = require("fs"); var xml = fs.readFileSync("signed.xml").toString(); var doc = new dom().parseFromString(xml); // DO NOT attempt to parse whatever data object you have here in `doc` // and then use it to verify the signature. This can lead to security issues. // i.e. BAD: parseAssertion(doc), // good: see below var signature = select( doc, "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", )[0]; var sig = new SignedXml({ publicCert: fs.readFileSync("client_public.pem") }); sig.loadSignature(signature); try { var res = sig.checkSignature(xml); } catch (ex) { console.log(ex); } ``` -------------------------------- ### Sign XML Document with xml-crypto Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Use this code to sign an XML document. Ensure you have a 'client.pem' file for the private key. The output will be saved to 'signed.xml'. ```javascript var SignedXml = require("xml-crypto").SignedXml, fs = require("fs"); var xml = "" + "" + "Harry Potter" + "" + ""; var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") }); sig.addReference({ xpath: "//*[local-name(.)='book']", 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 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; sig.computeSignature(xml); fs.writeFileSync("signed.xml", sig.getSignedXml()); ``` -------------------------------- ### Convert PFX Certificate to PEM Format Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Use the openssl command-line tool to convert a .pfx certificate file to the PEM format, which is required for signing operations. ```shell openssl pkcs12 -in c:\certs\yourcert.pfx -out c:\certs\cag.pem ``` -------------------------------- ### Implement Custom Signature Algorithm Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Create a custom signature algorithm by providing a getSignature method for signing the SignedInfo and a getAlgorithmName method. This is used for custom signing processes. ```javascript function MySignatureAlgorithm() { /*sign the given SignedInfo using the key. return base64 signature value*/ this.getSignature = function (signedInfo, privateKey) { return "signature of signedInfo as base64..."; }; this.getAlgorithmName = function () { return "http://mySigningAlgorithm"; }; } ``` -------------------------------- ### Sign XML with Signature Prefix Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Compute a signature for an XML document and add a specified prefix to the signature element using the `prefix` option in `computeSignature`. ```javascript var SignedXml = require("xml-crypto").SignedXml, fs = require("fs"); var xml = "" + "" + "Harry Potter" + "" + ""; var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") }); sig.addReference({ xpath: "//*[local-name(.)='book']", 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 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; sig.computeSignature(xml, { prefix: "ds", }); ``` -------------------------------- ### Implement Custom Transformation Algorithm Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Define a custom transformation algorithm by implementing the process and getAlgorithmName methods. The process method should return the canonical representation of a node after transformation. ```javascript function MyTransformation() { /*given a node (from the xmldom module) return its canonical representation (as string)*/ this.process = function (node) { //you should apply your transformation before returning return node.toString(); }; this.getAlgorithmName = function () { return "http://myTransformation"; }; } ``` -------------------------------- ### Implement Custom Asynchronous Signature Algorithm Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Create a custom asynchronous signature algorithm for signing documents with external services or HSMs. The `getSignature` method should perform asynchronous operations and call back with the result. ```javascript function AsyncSignatureAlgorithm() { this.getSignature = function (signedInfo, privateKey, callback) { var signer = crypto.createSign("RSA-SHA1"); signer.update(signedInfo); var res = signer.sign(privateKey, "base64"); //Do some asynchronous things here callback(null, res); }; this.getAlgorithmName = function () { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; }; } var sig = new SignedXml({ signatureAlgorithm: "http://asyncSignatureAlgorithm" }); sig.SignatureAlgorithms["http://asyncSignatureAlgorithm"] = AsyncSignatureAlgorithm; sig.signatureAlgorithm = "http://asyncSignatureAlgorithm"; sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#"; sig.computeSignature(xml, opts, function (err) { var signedResponse = sig.getSignedXml(); }); ``` -------------------------------- ### Verifying XML Documents Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Methods for loading a signature and checking its validity against an XML document. ```APIDOC ## loadSignature ### Description Loads the signature for verification. ### Method `loadSignature(signatureXml)` ### Parameters #### `signatureXml` (string or object) - A string or node object (like an [xmldom](https://github.com/xmldom/xmldom) node) containing the XML representation of the signature. ``` ```APIDOC ## checkSignature ### Description Validates the given XML document against the loaded signature. ### Method `checkSignature(xml)` ### Parameters #### `xml` (string) - A string containing the XML document to validate. ``` -------------------------------- ### Implement Custom Digest Algorithm Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Define a custom digest algorithm by implementing the getHash and getAlgorithmName methods. Use this when a non-standard hashing method is required. ```javascript function MyDigest() { this.getHash = function (xml) { return "the base64 hash representation of the given xml string"; }; this.getAlgorithmName = function () { return "http://myDigestAlgorithm"; }; } ``` -------------------------------- ### Register Custom Algorithms Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Register the custom transformation, canonicalization, digest, and signature algorithms with the SignedXml object to make them available for use. ```javascript /*register all the custom algorithms*/ signedXml.CanonicalizationAlgorithms["http://MyTransformation"] = MyTransformation; signedXml.CanonicalizationAlgorithms["http://MyCanonicalization"] = MyCanonicalization; signedXml.HashAlgorithms["http://myDigestAlgorithm"] = MyDigest; signedXml.SignatureAlgorithms["http://mySigningAlgorithm"] = MySignatureAlgorithm; ``` -------------------------------- ### Signing XML Documents Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Methods for adding references and computing the signature of an XML document. ```APIDOC ## addReference ### Description Adds a reference to an XML element for signing. ### Method `addReference({ xpath, transforms, digestAlgorithm, id, type })` ### Parameters #### Reference Object - **xpath** (string) - Required - A XPath expression referencing a XML element. - **transforms** (string[]) - Optional - An array of [transform algorithms](#canonicalization-and-transformation-algorithms). - **digestAlgorithm** (string) - Required - One of the supported [hashing algorithms](#hashing-algorithms). - **id** (string) - Optional - An `Id` attribute to add to the reference element. - **type** (string) - Optional - The `Type` attribute to add to the reference element (represented as a URI). ``` ```APIDOC ## computeSignature ### Description Computes the signature of the given XML document. ### Method `computeSignature(xml, [options])` ### Parameters #### `xml` (string) - A string containing a XML document. #### `options` (object) - **prefix** (string) - Optional - Adds this value as a prefix for the generated signature tags. - **attrs** (object) - Optional - A hash of attributes and values to add to the signature root node. - **location** (object) - Optional - Customize the location of the signature. Should contain `reference` (XPath expression) and `action` ('append', 'prepend', 'before', 'after'). - **existingPrefixes** (object) - Optional - A hash of prefixes and namespaces that already exist in the XML. ``` ```APIDOC ## getSignedXml ### Description Returns the original XML document with the signature included. Must be called after `computeSignature`. ### Method `getSignedXml()` ``` ```APIDOC ## getSignatureXml ### Description Returns only the signature part of the XML. Must be called after `computeSignature`. ### Method `getSignatureXml()` ``` ```APIDOC ## getOriginalXmlWithIds ### Description Returns the original XML with Id attributes added to relevant elements, required for validation. Must be called after `computeSignature`. ### Method `getOriginalXmlWithIds()` ``` -------------------------------- ### Specify Implicit Transforms for Verification Source: https://github.com/node-saml/xml-crypto/blob/master/README.md If signature verification fails, try specifying common implicit transforms in the `SignedXml` constructor options. This can help resolve issues caused by hidden transformations during the signing process. ```javascript var options = { implicitTransforms: ["http://www.w3.org/TR/2001/REC-xml-c14n-20010315"], publicCert: fs.readFileSync("client_public.pem"), }; var sig = new SignedXml(options); sig.loadSignature(signature); var res = sig.checkSignature(xml); ``` -------------------------------- ### Specify Signature Location in XML Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Control the placement of the signature within the XML document by using the `location` option in `computeSignature`. Options include appending, prepending, or inserting before/after a specific node. ```javascript const SignedXml = require("xml-crypto").SignedXml; const fs = require("fs"); const xml = "" + "" + "Harry Potter" + "" + ""; const sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") }); sig.addReference({ xpath: "//*[local-name(.)='book']", 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 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; sig.computeSignature(xml, { location: { reference: "//*[local-name(.)='book']", action: "after" }, // This will place the signature after the book element }); ``` -------------------------------- ### Extract Authenticated Data After Verification Source: https://github.com/node-saml/xml-crypto/blob/master/README.md After successful signature verification, use `getSignedReferences()` to obtain the data that was actually signed. Parse this data to ensure its integrity before use. Avoid using the `.getReferences()` API as it can be insecure. ```javascript if (!res) { throw "Invalid Signature"; } // good: The XML Signature has been verified, meaning some subset of XML is verified. var signedBytes = sig.getSignedReferences(); var authenticatedDoc = new dom().parseFromString(signedBytes[0]); // Take the first signed reference // It is now safe to load SAML, obtain the assertion XML, or do whatever else is needed. // Be sure to only use authenticated data. let signedAssertionNode = extractAssertion(authenticatedDoc); let parsedAssertion = parseAssertion(signedAssertionNode); return parsedAssertion; // This the correctly verified signed Assertion // BAD example: DO not use the .getReferences() API. ``` -------------------------------- ### Add Custom Objects to XML Signature Source: https://github.com/node-saml/xml-crypto/blob/master/README.md Use the `objects` option when creating a SignedXml instance to include custom data within the signature. Ensure the object's ID is correctly referenced in the signature. ```javascript const SignedXml = require("xml-crypto").SignedXml; const fs = require("fs"); const xml = "" + "" + "Harry Potter" + "" + ""; const sig = new SignedXml({ privateKey: fs.readFileSync("client.pem"), canonicalizationAlgorithm: "http://www.w3.org/2001/10/xml-exc-c14n#", signatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", objects: [ { content: "Test data in Object", attributes: { Id: "Object1", MimeType: "text/xml", }, }, ], }); // Add a reference to the Object element sig.addReference({ xpath: "//*[@Id='Object1']", digestAlgorithm: "http://www.w3.org/2001/04/xmlenc#sha256", transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"], }); sig.computeSignature(xml); fs.writeFileSync("signed.xml", sig.getSignedXml()); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.