Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

xadesjs

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

xadesjs

A pure Javascript implementation of XMLDSIG and XAdES based on Web Crypto

  • 1.0.1
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
989
decreased by-35.02%
Maintainers
1
Weekly downloads
 
Created
Source

XAdESjs

license Build Status NPM version

XAdES is short for "XML Advanced Electronic Signatures", it is a superset of XMLDSIG. This library aims to provide an implementation of both XMLDSIG and XAdES-BES 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).

There are seven different profiles of XAdES, they are:

  • Basic Electronic Signature (XAdES-BES)
  • XAdES with Timestamp (XAdES-T)
  • XAdES with Complete Validation Data (XAdES-C)
  • XAdES with Extended Validation Data (XAdES-X)
  • XAdES with Extended Long Term Validation Data (XAdES-X-L)
  • XAdES with Archiving Validation Data (XAdES-A)
  • XAdES with Explicit policy electronic signatures (XAdES-EPES)

They differ slightly based on what is included in the signature:

Provides Digital SignatureIncludes Cryptographic TimestampIncludes Revocation ReferencesIncludes Revocation DataAllows Secure Timestamp Countersignature
XAdES-BESYesNoNoNoNo
XAdES-EPESYesNoNoNoNo
XAdES-TYesYesNoNoNo
XAdES-CYesYesYesNoNo
XAdES-XYesYesYesNoNo
XAdES-X-LYesYesYesYesNo
XAdES-AYesYesYesYesYes
  • Only XAdES-BES is fully (as shown in BOLD) supported by XAdESjs
  • Other variants are supported by XAdESjs-PRO which is availible under a commercial license, email for more information

COMPATABILITY

CRYPTOGRAPHIC ALGORITHM SUPPORT

SHA1SHA2-256SHA2-384SHA2-512
RSASSA-PKCS1-v1_5XXXX
RSA-PSSXXXX
ECDSAXXXX
HMACXXXX

CANONICALIZATION ALGORITHM SUPPORT

  • XmlDsigC14NTransform
  • XmlDsigC14NWithCommentsTransform
  • XmlDsigExcC14NTransform
  • XmlDsigExcC14NWithCommentsTransform
  • XmlDsigEnvelopedSignatureTransform

PLATFORM SUPPORT

XAdESjs works with any browser that suppports 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. Thus polyfill is node-webcrypto-p11.

To use node-webcrypto-ossl you need to specify you want to use it, that looks like this:

var xadesjs = require("./built/xades.js");
var WebCrypto = require("node-webcrypto-ossl").default;

xadesjs.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 xadesjs = require("./built/xades.js");
var WebCrypto = require("node-webcrypto-p11").WebCrypto;

xadesjs.Application.setEngine("PKCS11", new WebCrypto({
    library: "/path/to/pkcs11.so",
	name: "Name of PKCS11 lib",
	slot: 0,
    sessionFlags: 2 | 4, // RW_SESSION | SERIAL_SESSION
	pin: "token pin"
}));

WARNING

Using XMLDSIG is a bit like running with scissors, that said it is needed for interoperability with a number of systems, for this reason, we have done this implementation.

Given the nuances in handling XMLDSIG securely at this time you should consider this solution suitable for research and experimentation, further code and security review is needed before utilization in a production application.

EXAMPLES

Create XMLDSIG Signature

In Node
var xadesjs = require("./built/xades.js");
var DOMParser = require("xmldom").DOMParser;
var XMLSerializer = require("xmldom").XMLSerializer;
var WebCrypto = require("node-webcrypto-ossl").default;

xadesjs.Application.setEngine("OpenSSL", new WebCrypto());

// Generate RSA key pair
var privateKey, publicKey;
xadesjs.Application.crypto.subtle.generateKey(
    {
        name: "RSASSA-PKCS1-v1_5",
        modulusLength: 1024, //can be 1024, 2048, or 4096,
        publicExponent: new Uint8Array([1, 0, 1]),
        hash: { name: "SHA-1" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
    },
    false, //whether the key is extractable (i.e. can be used in exportKey)
    ["sign", "verify"] //can be any combination of "sign" and "verify"
)
    .then(function (keyPair) {
        // Push ganerated keys to global variable
        privateKey = keyPair.privateKey;
        publicKey = keyPair.publicKey;

        // Call sign function
        var xmlString = '<player bats="left" id="10012" throws="right">\n\t<!-- Here\'s a comment -->\n\t<name>Alfonso Soriano</name>\n\t<position>2B</position>\n\t<team>New York Yankees</team>\n</player>';
        return SignXml(xmlString, privateKey, { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-1" } });
    })
    .then(function (signedDocument) {
        console.log("Signed document:\n\n", signedDocument);
    })
    .catch(function (e) {
        console.error(e);
    });


function SignXml(xmlString, key, algorithm) {
    return new Promise(function (resolve, reject) {
        var xmlDoc = new DOMParser().parseFromString(xmlString, "application/xml");
        var signedXml = new xadesjs.SignedXml(xmlDoc);

        // Add the key to the SignedXml document.
        signedXml.SigningKey = key;

        // Create a reference to be signed.
        var reference = new xadesjs.Reference();
        reference.Uri = "";

        // Add an enveloped transformation to the reference.
        reference.AddTransform(new xadesjs.XmlDsigEnvelopedSignatureTransform());

        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);

        // Add KeyInfo
        signedXml.KeyInfo = new xadesjs.KeyInfo();
        var keyInfoClause = new xadesjs.RsaKeyValue();
        signedXml.KeyInfo.AddClause(keyInfoClause);

        // Set prefix for Signature namespace
        signedXml.Prefix = "ds";

        // Compute the signature.
        signedXml.ComputeSignature(algorithm)
            .then(function () {
                return keyInfoClause.importKey(publicKey);
            })
            .then(function () {
                // Append signature
                var xmlDigitalSignature = signedXml.GetXml();
                xmlDoc.documentElement.appendChild(xmlDigitalSignature);

                // Serialize XML document
                var signedDocument = new XMLSerializer().serializeToString(xmlDoc);

                return Promise.resolve(signedDocument);
            })
            .then(resolve, reject);
    })
}
In the browser
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <title>XADESJS Signature Sample</title>
</head>

<body>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/ASN1.js/master/org/pkijs/common.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/ASN1.js/master/org/pkijs/asn1.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/PKI.js/master/org/pkijs/x509_schema.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/PKI.js/master/org/pkijs/x509_simpl.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/PeculiarVentures/xadesjs/master/built/xades.js"></script>
    
    <script type="text/javascript">
        // Generate RSA key pair
        var privateKey, publicKey;
        window.crypto.subtle.generateKey(
        {
            name: "RSASSA-PKCS1-v1_5",
            modulusLength: 2048, //can be 1024, 2048, or 4096
            publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
        },
        false, //whether the key is extractable (i.e. can be used in exportKey)
        ["sign", "verify"] //can be any combination of "sign" and "verify"
        )
        .then(function(keyPair){
            // Push ganerated keys to global variable
            privateKey = keyPair.privateKey;
            publicKey = keyPair.publicKey;
            console.log("Sucessfully generate key");
            
            // Call sign function
            var xmlString = '<player bats="left" id="10012" throws="right">\n\t<!-- Here\'s a comment -->\n\t<name>Alfonso Soriano</name>\n\t<position>2B</position>\n\t<team>New York Yankees</team>\n</player>';
            return SignXml(xmlString, privateKey, { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-1" } });
        })
        .then(function (signedDocument) {
            console.log("Successfully signed document:\n\n", signedDocument);
        })
        .catch(function (e) {
            console.error(e);
        });

        function SignXml(xmlString, key, algorithm) {
            return new Promise(function (resolve, reject) {
                var xmlDoc = new DOMParser().parseFromString(xmlString, "application/xml");
                var signedXml = new xadesjs.SignedXml(xmlDoc);

                // Add the key to the SignedXml document.
                signedXml.SigningKey = key;

                // Create a reference to be signed.
                var reference = new xadesjs.Reference();
                reference.Uri = "";

                // Add an enveloped transformation to the reference.
                reference.AddTransform(new xadesjs.XmlDsigEnvelopedSignatureTransform());

                // Add the reference to the SignedXml object.
                signedXml.AddReference(reference);

                // Add KeyInfo
                signedXml.KeyInfo = new xadesjs.KeyInfo();
                var keyInfoClause = new xadesjs.RsaKeyValue();
                signedXml.KeyInfo.AddClause(keyInfoClause);

                // Set prefix for Signature namespace
                signedXml.Prefix = "ds";

                // Compute the signature.
                signedXml.ComputeSignature(algorithm)
                    .then(function () {
                        return keyInfoClause.importKey(publicKey);
                    })
                    .then(function () {
                        // Append signature
                        var xmlDigitalSignature = signedXml.GetXml();
                        xmlDoc.documentElement.appendChild(xmlDigitalSignature);

                        // Serialize XML document
                        var signedDocument = new XMLSerializer().serializeToString(xmlDoc);

                        return Promise.resolve(signedDocument);
                    })
                    .then(resolve, reject);
            })
        }
    </script>
</body>
</html>

Check XMLDSIG Signature

In Node
var xadesjs = require("./built/xades.js");
var DOMParser = require("xmldom").DOMParser;
var WebCrypto = require("node-webcrypto-ossl").default;

xadesjs.Application.setEngine("OpenSSL", new WebCrypto());

var fs = require("fs");
var xmlString = fs.readFileSync("./xadesjs/test/static/valid_signature.xml","utf8");

var signedDocument = new DOMParser().parseFromString(xmlString, "application/xml");
var xmlSignature = signedDocument.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");

var signedXml = new xadesjs.SignedXml(signedDocument);
signedXml.LoadXml(xmlSignature[0]);
signedXml.CheckSignature()
.then(function (signedDocument) {
        console.log("Successfully Verified");
})
.catch(function (e) {
        console.error(e);
});
In the browser
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <title>XADESJS Verify Sample</title>
</head>

<body>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/ASN1.js/master/org/pkijs/common.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/ASN1.js/master/org/pkijs/asn1.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/PKI.js/master/org/pkijs/x509_schema.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/GlobalSign/PKI.js/master/org/pkijs/x509_simpl.js"></script>
    <script type="text/javascript" src="https://cdn.rawgit.com/PeculiarVentures/xadesjs/master/built/xades.js"></script>
    
    <script type="text/javascript">
        fetch("https://cdn.rawgit.com/PeculiarVentures/xadesjs/master/test/static/valid_signature.xml")
        .then(function(response) {
            return response.text()
        }).then(function(body) {
            var xmlString = body;
            
            var signedDocument = new DOMParser().parseFromString(xmlString, "application/xml");
            var xmlSignature = signedDocument.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");

            var signedXml = new xadesjs.SignedXml(signedDocument);
            signedXml.LoadXml(xmlSignature[0]);
            signedXml.CheckSignature()
            .then(function (signedDocument) {
                    console.log("Successfully Verified");
            })
            .catch(function (e) {
                    console.error(e);
            });
        })
    </script>
</body>
</html>

TESTING

In NodeJS:

npm test

In the browser

To run the browser test you need to run the server, from the test directory run:

npm start

And the then browse to `http://localhost:3000'.

THANKS AND ACKNOWLEDGEMENT

This project takes inspiration (style, approach, design and code) from both the Mono System.Security.Cryptography.Xml implementation as well as xml-crypto.

Keywords

FAQs

Package last updated on 15 Aug 2016

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc