-
Notifications
You must be signed in to change notification settings - Fork 189
Add XmlDSigVerifier wrapper for SignedXml #519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
shunkica
wants to merge
2
commits into
node-saml:master
Choose a base branch
from
shunkica:signer-validator-separation
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| v22.16.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| # XmlDSigVerifier Usage Guide | ||
|
|
||
| `XmlDSigVerifier` provides a focused, secure, and easy-to-use API for verifying XML signatures. It is designed to replace direct usage of `SignedXml` for verification scenarios, offering built-in security checks and a simplified configuration. | ||
|
|
||
| ## Features | ||
|
|
||
| - **Type-Safe Configuration:** Explicit options for different key retrieval strategies (Public Certificate, KeyInfo, Shared Secret). | ||
| - **Enhanced Security:** Built-in checks for certificate expiration, truststore validation, and limits on transform complexity. | ||
| - **Flexible Error Handling:** Choose between throwing errors or returning a result object. | ||
|
|
||
| ## Installation | ||
|
|
||
| Ensure you have `xml-crypto` installed: | ||
|
|
||
| ```bash | ||
| npm install xml-crypto | ||
| ``` | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ### 1. Verifying with a Public Certificate | ||
|
|
||
| If you already have the public certificate or key and want to verify a document signed with the corresponding private key: | ||
|
|
||
| ```typescript | ||
| import { XmlDSigVerifier } from "xml-crypto"; | ||
| import * as fs from "fs"; | ||
|
|
||
| const xml = fs.readFileSync("signed_document.xml", "utf-8"); | ||
| const publicCert = fs.readFileSync("public_key.pem", "utf-8"); | ||
|
|
||
| const result = XmlDSigVerifier.verifySignature(xml, { | ||
| keySelector: { publicCert: publicCert }, | ||
| }); | ||
|
|
||
| if (result.success) { | ||
| console.log("Signature valid!"); | ||
| // Access the signed content securely | ||
| console.log("Signed references:", result.signedReferences); | ||
| } else { | ||
| console.error("Verification failed:", result.error); | ||
| } | ||
| ``` | ||
|
|
||
| ### 2. Verifying using KeyInfo (with Truststore) | ||
|
|
||
| When the XML document contains the certificate in a `<KeyInfo>` element, you can verify it while ensuring the certificate is trusted and valid. | ||
|
|
||
| ```typescript | ||
| import { XmlDSigVerifier, SignedXml } from "xml-crypto"; | ||
| import * as fs from "fs"; | ||
|
|
||
| const xml = fs.readFileSync("signed_with_keyinfo.xml", "utf-8"); | ||
| const trustedRootCert = fs.readFileSync("root_ca.pem", "utf-8"); | ||
|
|
||
| const result = XmlDSigVerifier.verifySignature(xml, { | ||
| keySelector: { | ||
| // Extract the certificate from KeyInfo | ||
| getCertFromKeyInfo: (keyInfo) => SignedXml.getCertFromKeyInfo(keyInfo), | ||
| }, | ||
| security: { | ||
| // Ensure the certificate is trusted by your root CA | ||
| truststore: [trustedRootCert], | ||
| // Automatically check if the certificate is expired | ||
| checkCertExpiration: true, | ||
| }, | ||
| }); | ||
|
|
||
| if (result.success) { | ||
| console.log("Signature is valid and trusted."); | ||
| } else { | ||
| console.log("Verification failed:", result.error); | ||
| } | ||
| ``` | ||
|
|
||
| ## Advanced Usage | ||
|
|
||
| ### Reusing the Verifier Instance | ||
|
|
||
| For better performance when verifying multiple documents with the same configuration, create an instance of `XmlDSigVerifier`. | ||
|
|
||
| ```typescript | ||
| const verifier = new XmlDSigVerifier({ | ||
| keySelector: { publicCert: myPublicCert }, | ||
| // Global security options | ||
| security: { maxTransforms: 2 }, | ||
| }); | ||
|
|
||
| const result1 = verifier.verifySignature(xml1); | ||
| const result2 = verifier.verifySignature(xml2); | ||
| ``` | ||
|
|
||
| ### Verification Options | ||
|
|
||
| The `verifySignature` method accepts an options object with the following structure: | ||
|
|
||
| ```typescript | ||
| interface XmlDSigVerifierOptions { | ||
| // STRATEGY: Choose one of the following key selectors | ||
| keySelector: | ||
| | { publicCert: string | Buffer } // Direct public key/cert | ||
| | { getCertFromKeyInfo: (node) => string | null } // Extract from XML | ||
| | { sharedSecretKey: string | Buffer }; // HMAC | ||
|
|
||
| // CONFIGURATION | ||
| idAttributes?: string[]; // e.g., ['Id', 'ID'] | ||
| throwOnError?: boolean; // Default: false (returns result object) | ||
|
|
||
| // SECURITY | ||
| security?: { | ||
| maxTransforms?: number; // Limit transforms (DoS protection) | ||
| checkCertExpiration?: boolean; // Check NotBefore/NotAfter (KeyInfo only) | ||
| truststore?: (string | Buffer)[]; // List of trusted CAs (KeyInfo only) | ||
|
|
||
| // Algorithm allow-lists | ||
| signatureAlgorithms?: Record<string, any>; | ||
| hashAlgorithms?: Record<string, any>; | ||
| // ... | ||
| }; | ||
| } | ||
| ``` | ||
|
|
||
| ### Error Handling | ||
|
|
||
| By default, `verifySignature` returns a result object. If you prefer to handle exceptions: | ||
|
|
||
| ```typescript | ||
| try { | ||
| const result = XmlDSigVerifier.verifySignature(xml, { | ||
| keySelector: { publicCert }, | ||
| throwOnError: true, // Will throw Error on failure | ||
| }); | ||
| // If code reaches here, signature is valid | ||
| } catch (e) { | ||
| console.error("Signature invalid:", e.message); | ||
| } | ||
| ``` | ||
|
|
||
| ### Handling Multiple Signatures | ||
|
|
||
| If a document contains multiple signatures, you must specify which one to verify by passing the signature node. | ||
|
|
||
| ```typescript | ||
| import { DOMParser } from "@xmldom/xmldom"; | ||
|
|
||
| const doc = new DOMParser().parseFromString(xml, "application/xml"); | ||
| const signatures = doc.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature"); | ||
|
|
||
| // Verify the second signature | ||
| const result = XmlDSigVerifier.verifySignature( | ||
| xml, | ||
| { | ||
| keySelector: { publicCert }, | ||
| }, | ||
| signatures[1], | ||
| ); | ||
| ``` |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.