Code Monkey home page Code Monkey logo

xmldsigjs's Introduction

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

INSTALLING

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

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

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(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

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

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 will need to use a Web Crypto CryptoKey. You can see examples for an example of how to do that.

Initiating in NodeJs

"use strict";

const WebCrypto = require("node-webcrypto-ossl");
const crypto = new WebCrypto();
const XmlDSigJs = require("xmldsigjs");

XmlDSigJs.Application.setEngine("OpenSSL", crypto);

Initiating in Browser

Get the latest version form unpkg.com/xmldsigjs

<script src="https://unpkg.com/xmldsigjs@<version>/build/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 
    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));

Checking a XMLDSIG Signature

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

Browser Verify Example

<!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>

TESTING

In NodeJS:

npm test

In the browser

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

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

xmldsigjs's People

Contributors

alexey-pelykh avatar blaskurain avatar fotisl avatar intribvadell avatar microshine avatar rmhrisk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xmldsigjs's Issues

One <Transform> and c14n

I am not very knowledgeable in signing and "crypto" but tried to get a solution running that is using Node.js for XML signature.

The XML signed is for a Peppol SMP (Peppol.eu) and a sample can be viewed here: http://smp.helger.com/iso6523-actorid-upis::9915:generixtest/services/busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1

I also tried xml-crypto but it is giving me the same issue. I need a signature according to this:
image

What I get though is a signature that has two Transforms:

       <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
          <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
        </ds:Transforms>

I need canonicalization as http://www.w3.org/2001/10/xml-exc-c14n# but I can only get http://www.w3.org/TR/2001/REC-xml-c14n-20010315 working to produce a valid signature. If I add the Canonicalization for c14n I end up with two <Transforms> which is not OK according to the specification...

Any pointers appreciated!

The code for now is:

async function signXML(xmlString, publicKeyPem, privateKeyPem) {
  const hash = 'SHA-1';
  const alg = {
    name: 'RSASSA-PKCS1-v1_5',
    hash
  };
  const keyDer = pem2der(privateKeyPem);
  const key = await crypto.subtle.importKey('pkcs8', keyDer, alg, false, [
    'sign'
  ]);
  const x509 = preparePem(publicKeyPem);

  // XAdES-EPES
  var xml = xmldsigjs.Parse(xmlString);

  var digSigXml = new xmldsigjs.SignedXml();

  const X509Data = new xmldsigjs.KeyInfoX509Data()
  X509Data.AddSubjectName(process.env.SMP_QVALIA_CN);
  digSigXml.XmlSignature.KeyInfo.Add(X509Data);

  // no-go...
  // digSigXml.CanonicalizationMethod = 'http://www.w3.org/2001/10/xml-exc-c14n#';

  const signature = await digSigXml.Sign(
    // Signing document
    alg, // algorithm
    key, // key
    xml, // document
    {
      // options
        references: [
          {
            hash,
            transforms: ['enveloped']
          },
        ],
        signerRole: {
          claimed: ['Supplier']
        },
        x509: [x509],
        signingCertificate: x509,
    }
  );

  // append signature
  xml.documentElement.appendChild(signature.GetXml());

  // serialize XML
  const oSerializer = new XMLSerializer();
  const sXML = oSerializer.serializeToString(xml);
  return sXML.toString();
}

Question about ApplyTransformers

I have doubts about this code:

xmldsigjs/src/signed_xml.ts

Lines 544 to 573 in 71e66d3

protected ApplyTransforms(transforms: XmlTransforms, input: Element): any {
let output: any = null;
transforms.Sort((a, b) => {
const c14nTransforms = [Transforms.XmlDsigC14NTransform, XmlDsigC14NWithCommentsTransform,
Transforms.XmlDsigExcC14NTransform, XmlDsigExcC14NWithCommentsTransform];
if (c14nTransforms.some((t) => a instanceof t)) {
return 1;
}
if (c14nTransforms.some((t) => b instanceof t)) {
return -1;
}
return 0;
}).ForEach((transform) => {
transform.LoadInnerXml(input);
if (transform instanceof Transforms.XmlDsigXPathTransform) {
transform.GetOutput();
} else {
output = transform.GetOutput();
}
});
// Apply C14N transform if Reference has only one transform EnvelopedSignature
if (transforms.Count === 1 && transforms.Item(0) instanceof Transforms.XmlDsigEnvelopedSignatureTransform) {
const c14n = new Transforms.XmlDsigC14NTransform();
c14n.LoadInnerXml(input);
output = c14n.GetOutput();
}
return output;
}

  1. Why there is "dummy" GetOutput call at 560?
  2. Why every transformer load initial xml (line 585) instead of the result returned by the predecessor? It look like only last transformer works.

Support for multiple content references to external files

The following error originates from a Verify call for the below Signature XML (only showing part).

XMLJS0013: Cryptographic error: Invalid digest for uri 'IMG_20220116_135705.pdf'. Calculated digest is 8RUznvhXPPgFXxuSDjwykoPalhwl169wKkB61BL91cA= but the xml to validate supplies digest aKLKqgWvTDEbgdEMcb4371r13OuQthbTTFeFuFdFh3M=

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="S1">
    <ds:SignedInfo Id="S1-SignedInfo">
        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
        <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
        <ds:Reference Id="S1-ref-1" URI="IMG_20220116_135705.pdf">
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>aKLKqgWvTDEbgdEMcb4371r13OuQthbTTFeFuFdFh3M=</ds:DigestValue>
        </ds:Reference>
        <ds:Reference Id="S1-ref-SignedProperties" Type="http://uri.etsi.org/01903#SignedProperties" URI="#S1-SignedProperties">
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>vHMbu00YwhCyME2pBeGfd40CMZruW7cWjMGgzrsNkh4=</ds:DigestValue>
        </ds:Reference>
    </ds:SignedInfo>
Tracing the call

xmldsigjs/src/signed_xml.ts

Lines 183 to 204 in e823080

public async Verify(params?: CryptoKey | OptionsVerify) {
let content: DigestReferenceSource | undefined;
let key: CryptoKey | undefined;
if (params) {
if ("algorithm" in params && "usages" in params && "type" in params) {
key = params;
} else {
key = params.key;
content = params.content;
}
}
if (!content) {
const xml = this.document;
if (!(xml && xml.documentElement)) {
throw new XmlCore.XmlError(XmlCore.XE.NULL_PARAM, "SignedXml", "document");
}
content = xml.documentElement;
}
const res = await this.ValidateReferences(content);

xmldsigjs/src/signed_xml.ts

Lines 603 to 606 in e823080

protected async ValidateReferences(doc: DigestReferenceSource) {
for (const ref of this.XmlSignature.SignedInfo.References.GetIterator()) {
const digest = await this.DigestReference(doc, ref, false);
const b64Digest = XmlCore.Convert.ToBase64(digest);

Which then gets to the following where source is the signature XML document,

protected async DigestReference(source: DigestReferenceSource, reference: Reference, checkHmac: boolean) {

xmldsigjs/src/signed_xml.ts

Lines 381 to 392 in e823080

// we must not apply C14N transform to references out of the document
// e.g. non-xml documents
if (reference.Uri && reference.Uri[0] !== `#`) {
if (isElement(source)) {
if (!source.ownerDocument) {
throw new Error("Cannot get ownerDocument from the XML document");
}
canonOutput = new XMLSerializer().serializeToString(source.ownerDocument);
} else {
canonOutput = BufferSourceConverter.toArrayBuffer(source);
}
} else {

The solution is passing in an array buffer with the data, but this is only a partial solution!

    var xmlSignature = signedDocument.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");
    var signedXml = new XAdES.SignedXml(signedDocument);

    signedXml.LoadXml(xmlSignature[0]);
    console.log(signedXml);
    zf.getEntries().then((entries) => {
      return entries.find(
        (entry) => entry.filename == "IMG_20220116_135705.pdf"
      ).getData(new BlobWriter()).then(
        (blob) => blob.arrayBuffer()
      ).then((data) => {
        console.log(data);
        return signedXml.Verify({
          content: data
        })
      })
    })

Some signature documents might have multiple external references, so content should support multiple "files"

How to setEngine for OpenSSL without node-webcrypto-ossl

The README.md for this project still heavily refers to the node-webcrypto-ossl package, however it is deprecated in favour of the native node:crypto/webcrypto package.

So I am curious how I would change my code in order to support this?

Previously I would do this:

import WebCrypto from 'node-webcrypto-ossl';
import * as XmlDSigJs from 'xmldsigjs';

XmlDSigJs.Application.setEngine('OpenSSL', new WebCrypto() as unknown as Crypto);

Or is this no longer required after a certain version of xmldsigjs ? It's not very clear in the documentation.

Cannot apply transform to SignedProperties

Can someone please help me figure out which options I need to pass to the signing function to get the following output:

<ds:SignedInfo>
	<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
	<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
	<ds:Reference Id="DataReferenceId" URI="#CV1200520123456789000112345678901112345678904">
		<ds:Transforms>
			<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
		</ds:Transforms>
		<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
		<ds:DigestValue>ozcoAydr6KqHP+OtogQTxJIByzCzzWm8gNAOkpwBLMs=</ds:DigestValue>
	</ds:Reference>
	<ds:Reference URI="#SignedPropertiesId" Type="http://uri.etsi.org/01903#SignedProperties">
		<ds:Transforms>
			<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n"/>
		</ds:Transforms>
		<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
		<ds:DigestValue>xtFg15YLHtpf7KIhN0naU80wzSr99+17PXcVobbqEjc=</ds:DigestValue>
	</ds:Reference>
</ds:SignedInfo>

Namespace prefix on root creates invalid signatures

Working through my issues trying to solve the Peppol (Peppol.eu) standard signature I realized that the signature becomes invalid if the root element has a namespace prefix...

This snippet generates a valid signature:

  let xml2 = xmldsigjs.Parse(`<?xml version="1.0" encoding="UTF-8"?>
<SignedServiceMetadata xmlns="http://www.w3.org/2005/08/addressing" xmlns:ns2="http://busdox.org/serviceMetadata/publishing/1.0/">
  <ns2:xml>
    <test>hello</test>
  </ns2:xml>
</SignedServiceMetadata>
`);

But adding the prefix to the root generates a invalid signature:

  let xml2 = xmldsigjs.Parse(`<?xml version="1.0" encoding="UTF-8"?>
<ns2:SignedServiceMetadata xmlns="http://www.w3.org/2005/08/addressing" xmlns:ns2="http://busdox.org/serviceMetadata/publishing/1.0/">
  <xml>
    <test>hello</test>
  </xml>
</ns2:SignedServiceMetadata>
`);

How to use new XmlDSigJs.SignedXml()?

I'm trying using the method new XmlDSigJs.SignedXml(), but yet I'm passing parameters e properties like 'name' and even so I'm receiving '(node:26652) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'name' of undefined' as return. Could someone help with that?

Too Complicated for beginners

Hi,

I wanted to sign a simple xml using your library. I had xml, public key, private key and x509 certificates as file. I believe it follows some standard but its too complicated to use. I had seen it being promoted in xml-crypto repository and thought I had give it a try.

Signature location

I'm trying to use xmldsigjs to sign some xml files with nodejs. If i haven't missed something the <Signature> node is always located under the root element:

<Root>...document...<Signature></Signature></Root>

I wonder if the API allows to place the signature element on a given path. We have to verify some documents and the signature must be located on a determined path. If not, would it be possible to get the signature
and place it manually or move it after sign?

<Root><SomeContainer>...<Signature></Signature></SomeContainer>...</Root>

FTBFS: Cannot find namespace 'XmlCore'

Hi, it looks like there are some problems with TypeScript imports in this package. When running node_modules/.bin/tsc in the root directory of the project, after npm install, we get this:

src/xml/transform.ts:28:37 - error TS2503: Cannot find namespace 'XmlCore'.

28 export interface ITransform extends XmlCore.IXmlSerializable {
                                       ~~~~~~~


Found 1 error.

Also, when building a package which depends on xmldsigjs:

node_modules/xmldsigjs/index.d.ts:738:41 - error TS2503: Cannot find namespace 'XmlCore'.

738     export interface ITransform extends XmlCore.IXmlSerializable {
                                            ~~~~~~~

node_modules/xmldsigjs/index.d.ts:941:41 - error TS2503: Cannot find namespace 'XmlCore'.

941         protected propagatedNamespaces: XmlCore.NamespaceManager;
                                            ~~~~~~~

node_modules/xmldsigjs/index.d.ts:944:38 - error TS2503: Cannot find namespace 'XmlCore'.

944         protected visibleNamespaces: XmlCore.NamespaceManager;
                                         ~~~~~~~

node_modules/xmldsigjs/index.d.ts:948:85 - error TS2503: Cannot find namespace 'XmlCore'.

948         constructor(withComments: boolean, excC14N: boolean, propagatedNamespaces?: XmlCore.NamespaceManager);
                                                                                        ~~~~~~~

node_modules/xmldsigjs/index.d.ts:960:63 - error TS2503: Cannot find namespace 'XmlCore'.

960         protected NormalizeString(input: string | null, type: XmlCore.XmlNodeType): string;
                                                                  ~~~~~~~

node_modules/xmldsigjs/index.d.ts:961:36 - error TS2503: Cannot find namespace 'XmlCore'.

961         protected IsTextNode(type: XmlCore.XmlNodeType): boolean;
                                       ~~~~~~~

node_modules/xmldsigjs/index.d.ts:1049:39 - error TS2503: Cannot find namespace 'XmlCore'.

1049     export class SignedXml implements XmlCore.IXmlSerializable {
                                           ~~~~~~~

node_modules/xmldsigjs/index.d.ts:1050:35 - error TS2503: Cannot find namespace 'XmlCore'.

1050         public Parent?: Element | XmlCore.XmlObject;
                                       ~~~~~~~

node_modules/xmldsigjs/index.d.ts:1084:45 - error TS2503: Cannot find namespace 'XmlCore'.

1084         protected GetSignatureNamespaces(): XmlCore.AssocArray<string>;
                                                 ~~~~~~~

node_modules/xmldsigjs/index.d.ts:1105:26 - error TS2503: Cannot find namespace 'XmlCore'.

1105     export const Select: XmlCore.SelectNodes;
                              ~~~~~~~


Found 10 errors

Looks like index.d.ts references a module that was not imported at the top.

digest correct in some xml files but not others

First, I experimented signing a simple one-liner xml file using xmlsectool, and verified it using xmldsigjs, xmlsectool, xmlsec1, all verifies correctly.

Then, I signed a multi-page XML file with multi-namespace using xmlsectool. xmlsectool and xmlsec1 verifies it correctly but xmldsigjs gives digest mismatch error:

"XMLJS0013: Cryptographic error: Invalid digest for uri ''.
Calculated digest is **** but the xml to validate supplies digest ****"

It's a lot of work to go through the multi-page multi-namespace XML to find out what exactly triggered the miscalculation of digest, but one thing for sure, it's not because of any variation in the <dsig:Signature> since there are no variations like number of sigatures or number of certificates or difference in <dsig:Reference>. There were only differences in the content being signed.


Here is the working case:

$ printf '<?xml version="1.0" encoding="UTF-8"?>\n<text>hello world</text>' > hello-world.xml 
$ /opt/xmlsectool-2.0.0/xmlsectool.sh --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 --inFile hello-world.xml --outFile hello-world-signed.xml --keystore shong.wang.p12 --keystoreType PKCS12 --key 1 --keyPassword shong.wang --signaturePosition LAST
INFO  XMLSecTool - Reading XML document from file 'hello-world.xml'
INFO  XMLSecTool - XML document parsed and is well-formed.
INFO  XMLSecTool - XML document successfully signed
INFO  XMLSecTool - XML document written to file /home/weiwu/IdeaProjects/TokenScript/examples/EntryToken/hello-world-signed.xml

The verification works:

$ node test-xmldsigjs.js 
Signature status: true

Where test-xmldsignjs.js is slightly modified from examples to check hello-world-signed.xml

test-xmldsigjs.js.txt


Here is the non-working case, signed with the same key/certificates, the test file is well-formed and validated against corresponding schemas:

long-test.xml.gz

Signing:

$ /opt/xmlsectool-2.0.0/xmlsectool.sh --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 --inFile long-test.xml --outFile long-test-signed.xml --keystore shong.wang.p12 --keystoreType PKCS12 --key 1 --keyPassword shong.wang --signaturePosition LAST
INFO  XMLSecTool - Reading XML document from file 'long-test.xml'
INFO  XMLSecTool - XML document parsed and is well-formed.
INFO  XMLSecTool - XML document successfully signed
INFO  XMLSecTool - XML document written to file /home/weiwu/IdeaProjects/TokenScript/examples/EntryToken/long-test-signed.xml

Resulting file:

long-test-signed.xml.gz

Verifying using xmlsectool (SUCCESS):

$ /opt/xmlsectool-2.0.0/xmlsectool.sh --verifySignature --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 --inFile long-test-signed.xml --keystore shong.wang.p12 --keystoreType PKCS12 --key 1 --keyPassword shong.wang 
INFO  XMLSecTool - Reading XML document from file 'long-test-signed.xml'
INFO  XMLSecTool - XML document parsed and is well-formed.
INFO  XMLSecTool - XML document signature verified.

Verifying using xmlsec1 (SUCCESS):

$ xmlsec1 --verify long-test-signed.xml 
OK
SignedInfo References (ok/all): 1/1
Manifests References (ok/all): 0/0

Verifying using xmldsigjs.js (file name updated to long-test-signed.xml) (FAILURE)
test-xmldsigjs.js.txt

$ node test-xmldsigjs.js 
XmlError {
  prefix: 'XMLJS',
  code: 13,
  name: 'XmlError',
  message: "XMLJS0013: Cryptographic error: Invalid digest for uri ''. Calculated digest is RsL4D/BpAQQ5k5MBbyhv+Ez7TJbBAXVwecUyit8w7pU= but the xml to validate supplies digest IaBPprnL25MstZmfJOg9R8iV+Ktu/qba6n3WxmhU1TQ=",
  stack: "Error: XMLJS0013: Cryptographic error: Invalid digest for uri ''. Calculated digest is RsL4D/BpAQQ5k5MBbyhv+Ez7TJbBAXVwecUyit8w7pU= but the xml to validate supplies digest IaBPprnL25MstZmfJOg9R8iV+Ktu/qba6n3WxmhU1TQ=\n" +
    '    at new XmlError (/home/weiwu/IdeaProjects/tokenscript/node_modules/xml-core/dist/index.js:216:22)\n' +
    '    at SignedXml.ValidateReferences (/home/weiwu/IdeaProjects/tokenscript/node_modules/xmldsigjs/build/index.js:2708:23)\n' +
    '    at async SignedXml.Verify (/home/weiwu/IdeaProjects/tokenscript/node_modules/xmldsigjs/build/index.js:2403:21)'
}

Update <X509Data>

Update class KeyInfoX509Data. It has wron impplementation for X509CRL

  • Apply collections

  • Apply XmlCore

  • Extend tests

Update KeyInfoX509Data class

Apply xml-core decorators for KeyInfoX509Data class. Decorators allows to change Converters for XML schemas without source code updating. Developers can apply their own Converters (e.g. X509Certificate can have 76 bytes row)

How Can I verify a file with a External Certificate file (.cer)

The XML I am trying to verify does not the certificate embedded into . The Certificate is provided as a separate file with .cer extension How can I verify such xml files ?

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<OfflinePaperlessKyc referenceId="xxx1">
	<UidData>
		<Poi dob="13-05-1996" e="58addfc92619fc23ac5faf3ec06e1148a271ae0dfe408a185e7084b9f68554cb" gender="M" m="01eea91afe8297357c1c367e25e4647a7e4ab50154e36d3c85d3470b366ec91f" name="xxxxxx"/>
		<Poa careof="xxxxx" country="India" dist="xxx" house="xxxx" landmark="Sector-8" loc="xxx" pc="xxxx" po="L B Colony" state="xxxxx" street="M V P Colony" subdist="xxxxxxxx" vtc="xxxx"/>
		<Pht>xxxxxxxx</Pht>
	</UidData>
	<Signature
		xmlns="http://www.w3.org/2000/09/xmldsig#">
		<SignedInfo>
			<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
			<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
			<Reference URI="">
				<Transforms>
					<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
				</Transforms>
				<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
				<DigestValue>OWeE4A7z5WgT+eHPDy9JpPvKYlotO27gUYrJXTbC954=</DigestValue>
			</Reference>
		</SignedInfo>
		<SignatureValue>iM2TBQj4hZh8m6EwErGwffRrVnd6k4amDM9z3wMUQQ+CGS9LCuJPdho5sb10qiEZjG5HyzhNVsW/
xenEUI6vJik1pGGftXgXQsRC8urx9ubddr7GUbUQw8eid+zhWmd0iJct5SNuR6mFlC0NSGRqtmzf
LX/pHqFWA3iC5qvQx5sVjf4aqMm5snYvOLOrPB78BFwHWM+7h794DnP/BlDuMgWlpKL3F7+cpjr3
ynkxwRBlls8jAiFsMiBfvdnIT+Rz/Kd6n4qXxJNjQT+FB3mHo/PRnN7I2733TdnzACKSJldcAaja
1JZKwT3wFPBwbavjdQGKGKu08iWbkFXTi7E4JQ==</SignatureValue>
	</Signature>
</OfflinePaperlessKyc>

Note : I have changed some values to 'xxxxx' to mask certain sensitive information, so this file cannot be validated, just attached for reference.

XmlDsigEnvelopedSignatureTransform shouldn't remove all found Signatures

Hello,

We are using xmldsig for epub signatures.xml signature generation. In the epub spec, the signatures file may contain multiple Signature elements. It may also contain a reference to the signatures.xml file itself which requires an enveloped signature to avoid recursion. See https://www.w3.org/publishing/epub32/epub-ocf.html#sec-container-metainf-signatures.xml

My understanding according to https://www.w3.org/TR/xmldsig-core1/#sec-EnvelopedSignature is that the envelope should only apply to the direct ancestor signature to which the enveloped transform has been applied (please correct me if I am misunderstanding). In other words, sibling Signature nodes should be left intact.

However, the XmlDsigEnvelopedSignatureTransform method removes all first-level ancestor Signature elements from the XML being transformed.

It's not clear to me how one would decern which Signature is the ancestor of the transform in this example, but I think the simplest approach would be to allow the passing of an ID to XmlDsigEnvelopedSignatureTransform.GetOutput() in order to scope the transform to a particular Signature.

e.g.

 public GetOutput(id): any {
        if (!this.innerXml) {
            throw new XmlError(XE.PARAM_REQUIRED, "innerXml");
        }

        let child = this.innerXml.firstChild;
        const signatures: Element[] = [];
        while (child) {
            if (isElement(child)
                && child.localName === XmlSignature.ElementNames.Signature
                && child.namespaceURI === XmlSignature.NamespaceURI) {
                if(id === undefined || id === child.id) {
                   signatures.push(child);
               }
            }
            child = child.nextSibling;
        }
        for (const signature of signatures) {
            signature.parentNode?.removeChild(signature);
        }
        return this.innerXml;
    }

This may be related to issue #37

And thank you!

package-lock.json seems broken

  1. git clone https://github.com/PeculiarVentures/xmldsigjs.git
  2. cd xmldsigjs
  3. npm install

We get the below error while trying to npm install:

npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/source-map-2e0c3d18/package.json'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/extend-shallow-323c422e/package.json'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/define-property-fd8ed66d/package.json'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/source-map-2e0c3d18/README.md'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/extend-shallow-323c422e/README.md'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/define-property-fd8ed66d/README.md'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/snapdragon-node-c6544d33/package.json'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/extend-shallow-323c422e/LICENSE'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/define-property-fd8ed66d/LICENSE'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/snapdragon-node-c6544d33/README.md'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/source-map-2e0c3d18/LICENSE'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/extend-shallow-323c422e/index.js'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/define-property-fd8ed66d/index.js'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/snapdragon-node-c6544d33/LICENSE'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/source-map-2e0c3d18/source-map.js'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/source-map-2e0c3d18/CHANGELOG.md'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/snapdragon-node-c6544d33/index.js'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/pkijs-d8614b61/build/CertificatePolicies.js'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/pkijs-d8614b61/build/CertificatePolicies.js.map'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/pkijs-d8614b61/build/CertificateRevocationList.js'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/pkijs-d8614b61/build/CertificateRevocationList.js.map'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/rollup-bb65dca1/dist/rollup.js'
npm WARN tar ENOENT: no such file or directory, open '/home/thewanderer/Devel/Node/xmldsigjs2/node_modules/.staging/typescript-dabae1aa/lib/typescriptServices.d.ts'
npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.0.tgz
npm ERR! 404 
npm ERR! 404  '[email protected]' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404 It was specified as a dependency of 'xmldsigjs2'
npm ERR! 404 
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/thewanderer/.npm/_logs/2019-12-12T12_11_58_951Z-debug.log

Removing package-lock.json resolves the issue. Has package-lock.json been mangled, or generated by a buggy version of npm? Perhaps dependencies have disappeared from npm, too?

Wrong result for REC-xml-c14n-20010315

Microsoft SignedXml has success on signature verification

xmldsigjs has incorrect implementation of XmlCanonicalizer for http://www.w3.org/TR/2001/REC-xml-c14n-20010315 algorithm

Microsoft SignedXml

<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />

xmldsigjs

<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>

How to verify when the signature is in a different file than the content?

I'm trying to verify some XML files in the browser. I have a file document.xml and a document.sign.xml which contains a reference tag that references the document like this

<Reference URI="document.xml">
    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <DigestValue>...</DigestValue>
</Reference>

I am trying to verify the document like this (xml is document.xml and sigXml is document.sign.xml):

const parsedDoc = Parse(xml)
const parsedSig = Parse(sigXml)

const signature = parsedSig.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#', 'Signature')

const signedXml = new SignedXml(parsedDoc)
signedXml.LoadXml(signature[0])

try {
  const res = await signedXml.Verify()
  console.log('signature status', res)
} catch (error) {
  console.log(error)
}

But I get an error every time that the digest values do not match
"XMLJS0013: Cryptographic error: Invalid digest for uri 'document.xml'. Calculated digest is ... but the xml to validate supplies digest ...

If I try to verify the signature with xmlsec1 --verify document.sign.xml it says the file is ok:

OK
SignedInfo References (ok/all): 1/1
Manifests References (ok/all): 0/0

How can I do this properly in the browser?

Cannot `Verify` signature with transforms applied

There does not appear to be any way to provide transform options to the .Verify method in order to successfully verify a signature with transforms. For example, the following signature (have omitted digest, signature, modulus, exponent, cert values) cannot be successfully verified using this package because there is no way to process/pass the two Transforms to Verify


<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#prefix-2022...01">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>/b...DIGEST VALUE...=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue> g...SIGNATURE VALUE...== </ds:SignatureValue>
<ds:KeyInfo>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus> 6... MODULUS VALUE...== </ds:Modulus>
<ds:Exponent>A..B</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
<ds:X509Data>
<ds:X509Certificate> MII.......CERTIFICATE VALUE...== </ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>

XML error

I installed webcrypto with npm by but still have issue when I try new XmlDSigJs.SignedXml().Sign(...)

XmlError {
  prefix: 'XMLJS',
  code: 14,
  name: 'XmlError',
  message: 'XMLJS0014: WebCrypto module is not found',
  stack: 'Error: XMLJS0014: WebCrypto module is not found\n' +
    '    at new XmlError (C:\\projects\\notr\\node_modules\\xml-core\\dist\\index.js:216:22)\n' +
    '    at Function.get crypto [as crypto] (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:22:19)\n' +
    '    at RsaKeyValue.importKey (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:1539:39)\n' +
    '    at KeyValue.importKey (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:1710:34)\n' +
    '    at SignedXml.ApplySignOptions (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:2656:28)\n' +
    '    at SignedXml.Sign (C:\\projects\\notr\\node_modules\\xmldsigjs\\build\\index.js:2360:20)\n' +
    '    at C:\\projects\\notr\\cryptXML.js:59:22'
}

Empty reference URI for enveloped signature

I was using this library for signing xml using the following: -

Signed XML is verified by vendor and they need empty URI or signature verification fails.

https://www.w3.org/TR/xmldsig-core/#sec-URI says

If the URI attribute is omitted altogether, the receiving application is expected to know the identity of the object.

I believe we should default to empty URI in case of enveloped signature and should make it possible to omit only by choice.

"Object's schema was not verified against input data for Certificate"

I am having an issue when trying to instantiate an x509 certificate. The error message is

"Object's schema was not verified against input data for Certificate"

E.G.

//der is a string
var derBuffer = str2ab(der);
new self.xmldsig.X509Certificate(derBuffer);

(str2ab from here)

The error seems to be coming from compareSchema, specifically it fails the following check:

if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber)

inputSchema.idBlock.tagNumber = 13
inputData.idBlock.tagNumber = 16

I get the same behavior if I pass in the the "Raw" (instead of the derBuffer) property of my CryptoX509CertificateProto. E.G.

new self.xmldsig.X509Certificate(cert.raw);

(The cert is loaded using Fortify and wsCrypto).

Signing appears works fine, however I am trying to get the X509 certificate to include it in the x509Data. My code is largely follows the example provided here

One of the notable differences is that I am using this in a browser based solution (and as mentioned, using fortify) and as such my setEngine call is as follows:

xmldsig.Application.setEngine("OpenSSL", self.wsCrypto);'

The certificate DER is

-----BEGIN CERTIFICATE-----
MIIGrjCCBZagAwIBAgIQWpruzwaO/CCgMw1a9sZ4NTANBgkqhkiG9w0BAQsFADCB
iDEbMBkGA1UEChMSU3ltYW50ZWMgQXVzdHJhbGlhMR8wHQYDVQQLExZGb3IgVEVT
VCBwdXJwb3NlcyBPTkxZMRcwFQYDVQQLEw5HYXRla2VlcGVyIFBLSTEvMC0GA1UE
AxMmR2F0ZWtlZXBlciBURVNUIEdlbmVyYWwgQ2F0ZWdvcnkgQ0EtRzMwHhcNMTgw
OTEyMDAwMDAwWhcNMjAwOTEyMjM1OTU5WjCBsTELMAkGA1UEBhMCQVUxGDAWBgNV
BAgTD05ldyBTb3V0aCBXYWxlczEUMBIGA1UEBxMLTW91bnQgQW5uYW4xHDAaBgNV
BAsUE1NpZ25pbmcgQ2VydGlmaWNhdGUxJzAlBgNVBAMTHldheW5lIFRlc3QgMjAx
ODA5MTIgMyBEYXZpZHNvbjErMCkGCSqGSIb3DQEJARYcd2F5bmUuZGF2aWRzb25A
c3ltcGxpLmNvbS5hdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI9P
PuYV0UWQYYUQt6CU6kXhblNxud4LOgToyV35ErfAHWpNEJ4+z9kdq4iE/RNlOG4u
ILBGffJOws0zH0qiLyYBz+XwetTBS3nh1rngn8QlYJCiJ+DzxxiWZ72wWzAE5toI
Q6o52HE2FCuPtEVWmkvpWnXty5JdC9cpsvKdu27VViGQqY2K7kQYmqcoiWRMAaQf
6z4W/TM4rWtLkUxIFrGsgXUw8Kwc8zFVTo2KCAJe1cuDDhZ9P6PJovSpiDW14xdD
oGzeUMJq4TT3iN1Nx6N2IfqKRciNXLE/pza851yAkz0gcozKOmmyFqlDLHp4sw+I
vW2EKUIcSgf4CCKqMjMCAwEAAaOCAucwggLjMAwGA1UdEwEB/wQCMAAwggE0BgNV
HR8EggErMIIBJzCCASOgggEfoIIBG4ZZaHR0cDovL2NybC5waWxvdC5zeW1hbnRl
Yy1nYXRla2VlcGVyLmNvbS5hdS9HYXRla2VlcGVyVEVTVEdlbmVyYWxDYXRlZ29y
eUczL0xhdGVzdENSTC5jcmyGgb1sZGFwOi8vZGlyZWN0b3J5LnBpbG90LnN5bWFu
dGVjLWdhdGVrZWVwZXIuY29tLmF1L2NuPUdhdGVrZWVwZXIgVEVTVCBHZW5lcmFs
IENhdGVnb3J5IENBLUczLG91PUdhdGVrZWVwZXIgUEtJLG91PUZvciBURVNUIHB1
cnBvc2VzIE9OTFksbz1TeW1hbnRlYyBBdXN0cmFsaWE/Y2VydGlmaWNhdGVyZXZv
Y2F0aW9ubGlzdDtiaW5hcnkwSAYIKwYBBQUHAQEEPDA6MDgGCCsGAQUFBzABhixo
dHRwOi8vb2NzcC5waWxvdC5zeW1hbnRlYy1nYXRla2VlcGVyLmNvbS5hdTAfBgNV
HSMEGDAWgBS+UEwKExTSBCPcnsdU2MvSsRpIrjAdBgNVHQ4EFgQUdM9Ldl0G7vAo
doHzOVSyfUZRrkUwDgYDVR0PAQH/BAQDAgeAMIHIBgNVHSAEgcAwgb0wfAYKKiSp
/LRjgk2HaDBuMDQGCCsGAQUFBwIBFihodHRwczovL3BraS1waWxvdC52ZXJpc2ln
bi5jb20uYXUvZ2svY3BzMDYGCCsGAQUFBwICMCoaKGh0dHBzOi8vcGtpLXBpbG90
LnZlcmlzaWduLmNvbS5hdS9nay9ycGEwPQYLKiSp/LRjgk2PUAEwLjAsBggrBgEF
BQcCAjAgGh5Jc3N1ZWQgZm9yIFRFU1QgcHVycG9zZXMgT05MWS4wJwYDVR0RBCAw
HoEcd2F5bmUuZGF2aWRzb25Ac3ltcGxpLmNvbS5hdTANBgYqJAGCTQIEAxYBMTAN
BgkqhkiG9w0BAQsFAAOCAQEAfvdLKoyJsc5fVrs1OKJduqYBzlQrpm5jeMIYEbVL
+nJ5j86EVDGxMGbZHx9NB+UKl01qZanauAoEb63+KkKaYyUI7zLy0JF/qIcuv1/i
xPkeV4+va+sgm3kj8WjsYu+dlXl2c6KSv099QYvXQUh/vCYOzbcGK5d2zqhf33kU
EY8rtLOBCETEYPfkSn0qeh/pR68ZR9LcYCVFII9M4jESwnPTfXjNQXRkq8QU4HRO
uxDYikSvZxLN1taVKJN1HU0mYw+vQhdQUYt16lf5Gw4E7h1fwEZm3b9rVochZkTn
nRHLFM+pna4smliB6uOzcYzsnF3YSbZh98f5lbZudWSpaw==
-----END CERTIFICATE-----

N.B. I'm using the xmldsig.js (UMD bundle module) as per the readme, however the source of the compareSchema code seems to be ASN1.js, and there's a similar issue here. The solution there did not work for me.

I'm at a bit of a loss to understand/debug this any further.

Please let me know if this issue should be in the ASN1.js repository.

How to set CanonicalizationMethod or default ?

How do you set the Canonicalization method for signing ? I need to set it to http://www.w3.org/2001/10/xml-exc-c14n
I've tried setting xmldsig.XmlSignature.DefaultCanonMethod
and also

    const keyInfoRef = new xmldsig.Reference("#foo");
    keyInfoRef.CanonicalizationMethod = 'http://www.w3.org/2001/10/xml-exc-c14n#';
    keyInfoRef.DigestMethod.Algorithm = xmldsig.SHA1_NAMESPACE;
    signedXml.XmlSignature.SignedInfo.References.Add(keyInfoRef);

but the XML produced always says

        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>

What is the magic needed ?

canonicalization result incorrect if default `xmlns` presents and text node contains `&amp;`

This javascript can reproduce the problem. Put it under the project root directory. It first try to canonicalize a very short XML piece with xmlns.

Run it and observe that &amp; in a text node is incorrectly replaced with &amp;amp;, then it shows by removing xmlns on the root element the canonicalization is correct.

The test code:

"use strict";

const XmlDSigJs = require("xmldsigjs");
var WebCrypto = require("node-webcrypto-ossl");
var crypto = new WebCrypto.Crypto();

XmlDSigJs.Application.setEngine("WebCrypto", crypto);

let xml1 = `<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><script type="text/javascript">
let message = " &amp; ETH";</script></body></html>`;

let xml2 = `<html xml:lang="en"><body><script type="text/javascript">
let message = " &amp; ETH";</script></body></html> `;


function c14n(xml) {
	const elem = new DOMParser().parseFromString(xml, "application/xml");
	const xmlCanonicalizer = new XmlDSigJs.XmlCanonicalizer(true, false); // comment / exclusive
	const res = xmlCanonicalizer.Canonicalize(elem);
	return res;
}

console.log(c14n(xml1))
console.log(c14n(xml2))

The output (observe the &amp;amp; part right before ETH):

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><script type="text/javascript">
let message = " &amp;amp; ETH";</script></body></html>
<html xml:lang="en"><body><script type="text/javascript">
let message = " &amp; ETH";</script></body></html>

Signature\KeyInfo\KeyName support

Hello,

Looks like you have no native support of signatures, that do not publish key material (modulus, ...) like Signature\KeyInfo\KeyValue..., but have bilaterally shared key and use only its name to identify what key use to verify.

If i wrong pls give some advice how we have to use llb in described case.

Wbr!

"enveloped" canonicalization removes nested Signatures

When using this library with SAML, we've encountered an issue where signing a message that already contains a nested Signature will strip it before signing, yielding an invalid DigestValue, and thus an incorrect signature:

  1. Take a SAML Response XML document with node hierarchy: samlp:Response > samlp:Assertion
  2. Generate a signature for the Assertion node (using a Reference that points to it by ID)
  3. Place the resulting Signature element inside the Assertion
  4. Generate a signature for the entire Response, which should compute the hash from the entire canonicalized contents

Apparently, step 4. removes the nested Signature node before signing, which is incorrect - the node should only be replaced if it's a direct descendant of our node being signed.

This is caused by an overly-general XPath being used to find pre-existing Signatures. From the source of enveloped_signature.ts:

const signature = Select(this.innerXml, ".//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
        if (signature) {
            signature.parentNode!.removeChild(signature);
        }

Changing this to only match direct descendants (single slash instead of double) fixes the issue and prevents deeply-nested existing Signatures from being removed. The change is essential to enable proper SAML 2.0 support, because it often uses nested signatures in a scheme exactly like the one shown above.

modify default reference

its possible modify or add a transform in the Signature in the default reference?

    <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xades-id-123456">
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>xxxxxxxxxxxxxxxxxxx</ds:DigestValue>
    </ds:Reference>

Unclear issue with #Digest()

@microshine PeculiarVentures/PKI.js#136 (comment)
Digest() accepted both

const sha1 = xmldsigjs.CryptoConfig.GetHashAlgorithm('SHA-1')
const issuerNameHash = await sha1.Digest(Buffer.from(new Uint8Array(publicCertificateInfo.issuer.valueBeforeDecode)))

and

const sha1 = xmldsigjs.CryptoConfig.GetHashAlgorithm('SHA-1')
const issuerNameHash = await sha1.Digest(publicCertificateInfo.issuer.valueBeforeDecode)

yet gave completely different results and didn't complain, while

const issuerNameHash = crypto.createHash('sha1')
  .update(Buffer.from(new Uint8Array(publicCertificateInfo.issuer.valueBeforeDecode)))
  .digest()

complained about raw publicCertificateInfo.issuer.valueBeforeDecode

any insights what was going on?

Signed properties and SignedXml root element

@microshine one more thing, I'm not sure how to achieve that in my case root of signature.xml must be

<asic:XAdESSignatures xmlns:asic="http://uri.etsi.org/02918/v1.2.1#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#">
<ds:Signature/>
</asic:XAdESSignatures>

Yet it won't work just to include ds:Signature inside that block, since that will invalidate SignedProperties portion. Any insights on that matter?

problems compiling with typescript

Hi! 👋

Firstly, thanks for your work on this project! 🙂

I have a problem compiling this library with typescript backend (nestjs)

node_modules/xmldsigjs/build/types/xml/key_infos/x509_data.d.ts:58:9 - error TS2611: 'Key' is defined as a property in class 'KeyInfoClause', but is overridden here in 'KeyInfoX509Data' as an accessor.

temporary I add the following comment in the file x509_data.d.ts

// @ts-nocheck

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.