Nattily Primped Monster

    xmldisgjs
    TypeScript icon, indicating that this package has built-in type declarations

    2.0.1 • Public • Published

    XMLDSIGjs

    license CircleCI Coverage Status NPM version

    NPM

    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).

    COMPATABILITY

    CRYPTOGRAPHIC ALGORITHM SUPPORT

    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

    CANONICALIZATION ALGORITHM SUPPORT

    • XmlDsigC14NTransform
    • XmlDsigC14NWithCommentsTransform
    • XmlDsigExcC14NTransform
    • XmlDsigExcC14NWithCommentsTransform
    • XmlDsigEnvelopedSignatureTransform
    • XmlDsigBase64Transform

    PLATFORM SUPPORT

    XMLDSIGjs 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. 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"
    }));

    WARNING

    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.

    Usage

    Sign

    SignedXml.Sign(algorithmAlgorithm, keyCryptoKey, dataDocument, options?: OptionsSign)PromiseLike<Signature>;

    Parameters

    Name Description
    algorithm Signing Algorithm
    key Signing Key
    data XML document which must be signed
    options Additional options

    Options

    interface OptionsSign {
        /**
         * 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

    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.

    EXAMPLES

    For Sign/Verify operations you need to use CryptoKey. You can use examples for it

    Initiating in NodeJs

    "use strict";
     
    const WebCrypto = require("node-webcrypto-ossl");
    const crypto = new WebCrypto();
    const XmlCore = require("xml-core");
    const XmlDSigJs = require("xmldsigjs");
     
    XmlDSigJs.Application.setEngine("OpenSSL", crypto);

    Initiating in Browser

    <script src="asn1js.js"></script>
    <script src="pkijs.js"></script>
    <script src="xml-core.js"></script>
    <script src="xmldsig.js"></script>

    Creating a XMLDSIG Signature

    "use strict";
     
    let signature = new XmlDSigJs.SignedXml();
     
    signature.Sign(                                  // Signing document
        { name: "RSASSA-PKCS1-v1_5" },                        // algorithm 
        keys.privateKey,                                      // key 
        XmlCore.XmlObject.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));

    Checking a XMLDSIG Signature

    "use strict";
     
    let doc = XmlCore.XmlObject.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));

    Browser Verify Example

    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="utf-8"/>
        <title>XMLDSIGjs 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/xmldsigjs/master/built/xmldsig.js"></script> 
        
        <script type="text/javascript">
            fetch("https://cdn.rawgit.com/PeculiarVentures/xmldsigjs/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 xmldsigjs.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.

    RELATED

    Install

    npm i xmldisgjs

    DownloadsWeekly Downloads

    0

    Version

    2.0.1

    License

    MIT

    Last publish

    Collaborators

    • peculiarventures