XMLDSIG is short for "XML Digital Signature". This library aims to provide an implementation of XMLDSIG in Typescript/Javascript that uses Web Crypto for cryptographic operations so it can be used both in browsers and in Node.js (when used with a polyfill like node-webcrypto-ossl or node-webcrypto-p11).
npm install xmldsigjs
The npm module has build
folder with the following files:
Name | Size | Description |
---|---|---|
index.js | 105 Kb | CJS module with external modules |
index.es.js | 100 Kb | ES module with external modules |
xmldsig.js | 872 Kb | IIFE bundle module |
xmldsig.min.js | 398 Kb | minified IIFE bundled module |
SHA1 | SHA2-256 | SHA2-384 | SHA2-512 | |
---|---|---|---|---|
RSASSA-PKCS1-v1_5 | X | X | X | X |
RSA-PSS | X | X | X | X |
ECDSA | X | X | X | X |
HMAC | X | X | X | X |
- XmlDsigC14NTransform
- XmlDsigC14NWithCommentsTransform
- XmlDsigExcC14NTransform
- XmlDsigExcC14NWithCommentsTransform
- XmlDsigEnvelopedSignatureTransform
- XmlDsigBase64Transform
XMLDSIGjs works with any browser that supports Web Crypto. Since node does not have Web Crypto you will need a polyfill on this platform, for this reason the npm package includes node-webcrypto-ossl; browsers do not need this dependency and in those cases though it will be installed it will be ignored.
If you need to use a Hardware Security Module we have also created a polyfill for Web Crypto that supports PKCS #11. Our polyfill for this is node-webcrypto-p11.
To use node-webcrypto-ossl you need to specify you want to use it, that looks like this:
var xmldsigjs = require("xmldsigjs");
var WebCrypto = require("node-webcrypto-ossl");
xmldsigjs.Application.setEngine("OpenSSL", new WebCrypto());
The node-webcrypto-p11 polyfill will work the same way. The only difference is that you have to specify the details about your PKCS#11 device when you instansiate it:
var xmldsigjs = require("xmldsigjs");
var WebCrypto = require("node-webcrypto-p11");
xmldsigjs.Application.setEngine("PKCS11", new WebCrypto({
library: "/path/to/pkcs11.so",
name: "Name of PKCS11 lib",
slot: 0,
sessionFlags: 4, // SERIAL_SESSION
pin: "token pin"
}));
Using XMLDSIG is a bit like running with scissors so use it cautiously. That said it is needed for interoperability with a number of systems, for this reason, we have done this implementation.
SignedXml.Sign(algorithm: Algorithm, key: CryptoKey, data: Document, options?: OptionsSign): PromiseLike<Signature>;
Parameters
Name | Description |
---|---|
algorithm | Signing Algorithm |
key | Signing Key |
data | XML document which must be signed |
options | Additional options |
interface OptionsSign {
/**
* Id of Signature
*/
id?: string
/**
* Public key for KeyInfo block
*/
keyValue?: CryptoKey;
/**
* List of X509 Certificates
*/
x509?: string[];
/**
* List of Reference
* Default is Reference with hash alg SHA-256 and exc-c14n transform
*/
references?: OptionsSignReference[];
}
interface OptionsSignReference {
/**
* Id of Reference
*/
id?: string;
uri?: string;
/**
* Hash algorithm
*/
hash: AlgorithmIdentifier;
/**
* List of transforms
*/
transforms?: OptionsSignTransform[];
}
type OptionsSignTransform = "enveloped" | "c14n" | "exc-c14n" | "c14n-com" | "exc-c14n-com" | "base64";
Verify(key?: CryptoKey): PromiseLike<boolean>;
Parameters
Name | Description |
---|---|
key | Verifying Key. Optional. If key not set it looks for keys in KeyInfo element of Signature. |
For Sign/Verify operations you will need to use a Web Crypto CryptoKey. You can see examples for an example of how to do that.
"use strict";
const WebCrypto = require("node-webcrypto-ossl");
const crypto = new WebCrypto();
const XmlDSigJs = require("xmldsigjs");
XmlDSigJs.Application.setEngine("OpenSSL", crypto);
Get the latest version form unpkg.com/xmldsigjs
<script src="https://unpkg.com/xmldsigjs@<version>/build/xmldsig.js"></script>
"use strict";
let signature = new XmlDSigJs.SignedXml();
signature.Sign( // Signing document
{ name: "RSASSA-PKCS1-v1_5" }, // algorithm
keys.privateKey, // key
XmlDSigJs.Parse(xml), // document
{ // options
keyValue: keys.publicKey,
references: [
{ hash: "SHA-512", transforms: ["enveloped", "c14n"] },
]
})
.then(() => {
console.log(signature.toString()); // <xml> document with signature
})
.catch(e => console.log(e));
let doc = XmlDSigJs.Parse(xml);
let signature = doc.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");
let signedXml = new XmlDSigJs.SignedXml(doc);
signedXml.LoadXml(signature[0]);
signedXml.Verify()
.then(res => {
console.log("Signature status:", res); // Signature status: true
})
.catch(e => console.log(e));
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>XMLDSIGjs Verify Sample</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.7.0/polyfill.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/asmCrypto/2.3.2/asmcrypto.all.es5.min.js"></script>
<script src="https://cdn.rawgit.com/indutny/elliptic/master/dist/elliptic.min.js"></script>
<script src="https://unpkg.com/[email protected]/build/webcrypto-liner.shim.min.js"></script>
<script src="https://unpkg.com/[email protected]/build/xmldsig.js"></script>
<script type="text/javascript">
fetch("signature.xml")
.then(function(response) {
return response.text();
}).then(function(body) {
var xmlString = body;
var signedDocument = XmlDSigJs.Parse(xmlString);
var xmlSignature = signedDocument.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");
var signedXml = new XmlDSigJs.SignedXml(signedDocument);
signedXml.LoadXml(xmlSignature[0]);
signedXml.Verify()
.then(function (res) {
console.log((res ? "Valid" : "Invalid") + " signature");
})
.catch(function (e) {
console.error(e);
});
})
</script>
</body>
</html>
npm test
To run the browser test you need to run a test server, from the test directory run:
npm start
And the then browse to `http://localhost:3000'.
This project takes inspiration (style, approach, design and code) from both the Mono System.Security.Cryptography.Xml implementation as well as xml-crypto.
- Why XML Security is Broken
- XML Signature Syntax and Processing
- XML Security Algorithm Cross-Reference
- XMLDSIG HTML Signing Profile
- Canonical XML
- Exclusive XML Canonicalization
- Internet X.509 Public Key Infrastructure Time-Stamp Protocol
- PKIjs
- @peculiar/webcrypto
- node-webcrypto-ossl
- node-webcrypto-p11