node-saml / xml-crypto

Xml digital signature and encryption library for Node.js
MIT License
198 stars 171 forks source link

Wrong Digest Value generated. Actual XML and Expected XML is not matching. Working from last three nights. #212

Open niladrinic opened 4 years ago

niladrinic commented 4 years ago

Dear All, I have used this library to generate a signature which is done at root level. The signed xml is not matching as per the expected xml. The digested value and signature value is not matching with real real value. Can't figure this out working from last three night and almost gone mad. please help me out.

var builder = require('xmlbuilder');
var SignedXml = require('xml-crypto').SignedXml;
var fs = require("fs");

module.exports.SXML = function() {
    //Created the request XML as per the required format
    var xml = builder.create('Esign').att('AuthMode', '1').att('aspId', 'TNIC-001').att('kycId', '')
        .att('ekycIdType', 'A').att('responseSigType', "pkcs7")
        .att('responseUrl', 'https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1')
        .att('sc', 'Y').att('ts', '2020-05-19T11:28:01').att('txn', '999-ESIGN-DIVISION-2020-05-19T11:28:01')
        .att('ver', '2.1');
    //xml.ele("Docs").ele("InputHash",{'docInfo':'hello', 'hashAlgorithm':'SHA256', 'id':'1'},'5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e');
    xml.ele("Docs").ele("InputHash", {
        'docInfo': 'hello',
        'hashAlgorithm': 'SHA256',
        'id': '1'
    }, '5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e');

    // XML doc is ready for signing. Converted to String 
    var xmldoc = xml.toString({
        pretty: true
    });

    var sig = new SignedXml();
    //sig.addReference("/*",['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],'http://www.w3.org/2001/04/xmlenc#sha256','','','',true);
    sig.addReference("/*", ['http://www.w3.org/2000/09/xmldsig#enveloped-signature'], 'http://www.w3.org/2000/09/xmldsig#sha1', '', '', '', true);

    sig.signingKey = fs.readFileSync("nicesign.pem");
    sig.canonicalizationAlgorithm = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
    sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
    sig.computeSignature(xmldoc.toString());

    return sig.getSignedXml();
}

Output XML is:

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
  <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/2000/09/xmldsig#sha1"/>
        <DigestValue>4IoV5vTOEUL9jI4p5N2Z+oq6rgY=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>qQ4DZk+OZNMsalFk2J9ke9QEyv0FwqpBbY2k5s22JivHPuC0lbhxW0xAH7XOkTB4s6kJGL3sf1+Q19V8BL1uX62AgJeWukkQ9qWf72KmIVOT6DUqKDst2rFIZRLUSSNwBqfspzX2aQbHriImLll0LOAkha5bFAZSLlzClVDR0ULGkMEfVfe+e6p84b7zY5HRrH2nBXF1+37C/TUA7pLnUGqP9WILRyh4z+2qguhZTV5oqNWDCFJ1JfwxYJqr+1YVqhIc4AK6v0c3MmPRElH97t98D/R+NVqy3GpOCX9+LldqLJJbCoVnYWMOAb2Au1Cf1K0gg5GJpIjtEGIJT80dXA==</SignatureValue>
  </Signature>
</Esign>

Expected Output is: (Difference in digest value and even if the algorithm mentioned in this same as well as content of the XML)

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
  <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/2000/09/xmldsig#sha1"/>
        <DigestValue>4IoV5vTOEUL9jI4p5N2Z+oq6rgY=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>qQ4DZk+OZNMsalFk2J9ke9QEyv0FwqpBbY2k5s22JivHPuC0lbhxW0xAH7XOkTB4s6kJGL3sf1+Q19V8BL1uX62AgJeWukkQ9qWf72KmIVOT6DUqKDst2rFIZRLUSSNwBqfspzX2aQbHriImLll0LOAkha5bFAZSLlzClVDR0ULGkMEfVfe+e6p84b7zY5HRrH2nBXF1+37C/TUA7pLnUGqP9WILRyh4z+2qguhZTV5oqNWDCFJ1JfwxYJqr+1YVqhIc4AK6v0c3MmPRElH97t98D/R+NVqy3GpOCX9+LldqLJJbCoVnYWMOAb2Au1Cf1K0gg5GJpIjtEGIJT80dXA==</SignatureValue>
  </Signature>
</Esign>
djaqua commented 1 year ago

@niladrinic did you ever figure this out or do you still need help with it?

cjbarth commented 1 year ago

@niladrinic , I've pretty printed your code and used properly labeled fences to make it much easier to read. After pretty printing the XML, it appears that both are the same. If more help is needed, more information is needed. Please reply with more information to reopen this.

CarlaMck77 commented 1 year ago

I have a mismatched DigestValue and SignatureValue as well. I have no idea how to fix it. This is new to me.

Have you figured out what was causing this issue?

cfficaurzua commented 7 months ago

i have the same problem I checked byte by byte the digest value is indeed wrong other libraries with same configuration gets another value I also check with this tool https://tools.chilkat.io/xmlDsigVerify.cshtml

cjbarth commented 7 months ago

I am sorry that you're having issues. We certainly want to fix them, however, we don't have enough information to help. The original post lists the expected output as the exact same as the produced output, so we've got nothing to go on there. Please provide more information, sample code, received vs. expected, etc., otherwise there is nothing that anyone can do to help.

srd90 commented 7 months ago

Issue reporters didn't share anything to work with so lets try at least something.

At the time when issue was raised (based on timestamp) xml-crypto version was 1.5.3 and xmlbuilder is/was 15.1.1.

This gives us about following package.json

{
  "name": "foo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "xml-crypto": "1.5.3",
    "xmlbuilder": "15.1.1"
  }
}

BUT lets start by asking second opinion about Digest value from xmlsec1 tool:

#!/bin/bash

FOODIR=/tmp/xml-crypto-212
KEY=$FOODIR/nicesign.pem
CERT=$FOODIR/nicesign_cert.pem
KEYSTORE=$FOODIR/keystore.p12
TO_BE_SIGNED=$FOODIR/to_be_signed.xml
SIGNED=$FOODIR/signed.xml

mkdir -p $FOODIR

# https://github.com/node-saml/xml-crypto/issues/212
# didn't provide used signing key so lets use this as "nicesign.pem":
wget -O $KEY https://raw.githubusercontent.com/node-saml/xml-crypto/21201723d2ca9bc11288f62cf72552b7d659b000/test/static/client.pem

wget -O $CERT https://raw.githubusercontent.com/node-saml/xml-crypto/21201723d2ca9bc11288f62cf72552b7d659b000/test/static/client_public.pem

openssl \
  pkcs12 \
  -nodes \
  -export \
  -out $KEYSTORE \
  -inkey $KEY \
  -in $CERT \
  -passout pass:password

# content of XML document produced by https://github.com/node-saml/xml-crypto/issues/212
# augmented with "signing template" for xmlsec1. Content of signing template was deducted from
# output of issue report's code snippets output.
cat <<EOF >$TO_BE_SIGNED
<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
<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/2000/09/xmldsig#sha1"/><DigestValue/></Reference></SignedInfo><SignatureValue/></Signature></Esign>
EOF

xmlsec1 \
  --sign \
  --print-debug \
  --id-attr:ID Esign \
  --output $SIGNED \
  --pkcs12 $KEYSTORE \
  --pwd password \
  $TO_BE_SIGNED

cat $SIGNED

Script output is:

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
<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/2000/09/xmldsig#sha1"/><DigestValue>1vWDVKN2jliWtO825GBmO4M3il4=</DigestValue></Reference></SignedInfo><SignatureValue>jfWA3qHH0fWFbZCqUHKlu1oc/vcfVdOV8yZMlqNVkCgwpP7m2HjDLt2j0NZJzFLd
BBLMXxc/Qb96MUra5g8bfOsIHjDW1Qh+GLovd+PO79TpZ4TPNMxJNy/bT82bXpjn
T1QCH3hNT82NQ0gZ1kgwkVmSJ/hNmQXgD4Sp+5YiBT4=</SignatureValue></Signature></Esign>

and DigestValue is:

<DigestValue>1vWDVKN2jliWtO825GBmO4M3il4=</DigestValue>

if produced signed XML is pasted to https://tools.chilkat.io/xmlDsigVerify.cshtml it reports

Reference 1 digest is valid.

Pretty printed version of output signed xml for better readability

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
  <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/2000/09/xmldsig#sha1"/>
        <DigestValue>1vWDVKN2jliWtO825GBmO4M3il4=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>jfWA3qHH0fWFbZCqUHKlu1oc/vcfVdOV8yZMlqNVkCgwpP7m2HjDLt2j0NZJzFLd
BBLMXxc/Qb96MUra5g8bfOsIHjDW1Qh+GLovd+PO79TpZ4TPNMxJNy/bT82bXpjn
T1QCH3hNT82NQ0gZ1kgwkVmSJ/hNmQXgD4Sp+5YiBT4=</SignatureValue>
  </Signature>
</Esign>

Now lets try with code snippet from issue report

/*
Related to https://github.com/node-saml/xml-crypto/issues/212

Issue doesn't give any hint about any version thus reasoned
from timestamps that xml-crypto version might have been 1.5.3
and xmlbuilder might have been 15.1.1

Dunno about nodejs version. This investigation is done with
npm 6.14.18
node v14.21.3

and with following package.json
{
  "name": "foo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "xml-crypto": "1.5.3",
    "xmlbuilder": "15.1.1"
  }
}

Furthermore example code at issue https://github.com/node-saml/xml-crypto/issues/212
didn't have content of "nicesign.pem" thus used this key as "nicesign.pem"
https://raw.githubusercontent.com/node-saml/xml-crypto/21201723d2ca9bc11288f62cf72552b7d659b000/test/static/client.pem
*/
var nicesign_pem = `
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL4vpoH3H3byehjj
7RAGxefGRATiq4mXtzc9Q91W7uT0DTaFEbjzVch9aGsNjmLs4QHsoZbuoUmi0st4
x5z9SQpTAKC/dW8muzacT3E7dJJYh03MAO6RiH4LG34VRTq1SQN6qDt2rCK85eG4
5NHI4jceptZNu6Zot1zyO5/PYuFpAgMBAAECgYAhspeyF3M/xB7WIixy1oBiXMLY
isESFAumgfhwU2LotkVRD6rgNl1QtMe3kCNWa9pCWQcYkxeI0IzA+JmFu2shVvoR
oL7eV4VCe1Af33z24E46+cY5grxNhHt/LyCnZKcitvCcrzXExUc5n6KngX0mMKgk
W7skZDwsnKzhyUV8wQJBAN2bQMeASQVOqdfqBdFgC/NPnKY2cuDi6h659QN1l+kg
X3ywdZ7KKftJo1G9l45SN9YpkyEd9zEO6PMFaufJvZUCQQDbtAWxk0i8BT3UTNWC
T/9bUQROPcGZagwwnRFByX7gpmfkf1ImIvbWVXSpX68/IjbjSkTw1nj/Yj1NwFZ0
nxeFAkEAzPhRpXVBlPgaXkvlz7AfvY+wW4hXHyyi0YK8XdPBi25XA5SPZiylQfjt
Z6iN6qSfYqYXoPT/c0/QJR+orvVJNQJBANhRPNXljVTK2GDCseoXd/ZiI5ohxg+W
UaA/1fDvQsRQM7TQA4NXI7BO/YmSk4rW1jIeOxjiIspY4MFAIh+7UL0CQFL6zTg6
wfeMlEZzvgqwCGoLuvTnqtvyg45z7pfcrg2cHdgCXIy9kErcjwGiu6BOevEA1qTW
Rk+bv0tknWvcz/s=
-----END PRIVATE KEY-----
`

var builder = require('xmlbuilder');
var SignedXml = require('xml-crypto').SignedXml;
var fs = require("fs");

function SXML() { //module.exports.SXML = function() {

    //Created the request XML as per the required format
    var xml = builder.create('Esign').att('AuthMode', '1').att('aspId', 'TNIC-001').att('kycId', '')
        .att('ekycIdType', 'A').att('responseSigType', "pkcs7")
        .att('responseUrl', 'https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1')
        .att('sc', 'Y').att('ts', '2020-05-19T11:28:01').att('txn', '999-ESIGN-DIVISION-2020-05-19T11:28:01')
        .att('ver', '2.1');
    //xml.ele("Docs").ele("InputHash",{'docInfo':'hello', 'hashAlgorithm':'SHA256', 'id':'1'},'5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e');
    xml.ele("Docs").ele("InputHash", {
        'docInfo': 'hello',
        'hashAlgorithm': 'SHA256',
        'id': '1'
    }, '5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e');

    // XML doc is ready for signing. Converted to String 
    var xmldoc = xml.toString({
        pretty: true
    });

    var sig = new SignedXml();
    //sig.addReference("/*",['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],'http://www.w3.org/2001/04/xmlenc#sha256','','','',true);
    sig.addReference("/*", ['http://www.w3.org/2000/09/xmldsig#enveloped-signature'], 'http://www.w3.org/2000/09/xmldsig#sha1', '', '', '', true);

    sig.signingKey = nicesign_pem; // fs.readFileSync("nicesign.pem");
    sig.canonicalizationAlgorithm = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
    sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
    sig.computeSignature(xmldoc.toString());

    return sig.getSignedXml();
}

console.log(SXML());

Output signed XML is:

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
<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/2000/09/xmldsig#sha1"/><DigestValue>4IoV5vTOEUL9jI4p5N2Z+oq6rgY=</DigestValue></Reference></SignedInfo><SignatureValue>cPynLKSHAvTg90BueCU0PsHxoLqaF7U62nH19a5TWH2Wq1ohShKTF6adElSgnbyYllTgOiUQwAGb+T8gblxnOtMTOZdq3ktc1AbncrZ9PC75PVvlCiVP4Du/GRDgS+E0/PPb0Iuy3zzBGwMjE5qo5rCcjgfeGtoLgCsFw2HXaV8=</SignatureValue></Signature></Esign>

and DigestValue is:

<DigestValue>4IoV5vTOEUL9jI4p5N2Z+oq6rgY=</DigestValue>

if produced signed XML is pasted to https://tools.chilkat.io/xmlDsigVerify.cshtml it reports

Reference 1 digest is invalid because the computed digest differs from the digest in the XML.

Pretty printed version of output signed xml for better readability

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
  <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/2000/09/xmldsig#sha1"/>
        <DigestValue>4IoV5vTOEUL9jI4p5N2Z+oq6rgY=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>cPynLKSHAvTg90BueCU0PsHxoLqaF7U62nH19a5TWH2Wq1ohShKTF6adElSgnbyYllTgOiUQwAGb+T8gblxnOtMTOZdq3ktc1AbncrZ9PC75PVvlCiVP4Du/GRDgS+E0/PPb0Iuy3zzBGwMjE5qo5rCcjgfeGtoLgCsFw2HXaV8=</SignatureValue>
  </Signature>
</Esign>

FWIW,

  1. if xml-crypto 3.1.0 is used result is same.
  2. no point to try with 4.x and 5.x because those should be marked vulnerable and no-one should use those
  3. I did not have time to modify issue code snippet to work with xml-crypto 6.0.0

quick grepping around xml-crypto codebase about used algorithms it turned out that http://www.w3.org/TR/2001/REC-xml-c14n-20010315 is not explicitly tested.

Based on aforementioned observation searching issues which have string 20010315: https://github.com/node-saml/xml-crypto/issues?q=is%3Aissue+is%3Aopen+20010315

returned among other things https://github.com/node-saml/xml-crypto/issues/210 (tl;dr; with just enveloped-signature at transformatons array digest values mismatch but with enveloped-signature followed by REC-xml-c14n-20010315 digest values matched ).

Lets try to add REC-xml-c14n-20010315 to the transformations list:

/*
Related to https://github.com/node-saml/xml-crypto/issues/212

npm 6.14.18
node v14.21.3

{
  "name": "foo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "xml-crypto": "1.5.3",
    "xmlbuilder": "15.1.1"
  }
}
*/
var nicesign_pem = `
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL4vpoH3H3byehjj
7RAGxefGRATiq4mXtzc9Q91W7uT0DTaFEbjzVch9aGsNjmLs4QHsoZbuoUmi0st4
x5z9SQpTAKC/dW8muzacT3E7dJJYh03MAO6RiH4LG34VRTq1SQN6qDt2rCK85eG4
5NHI4jceptZNu6Zot1zyO5/PYuFpAgMBAAECgYAhspeyF3M/xB7WIixy1oBiXMLY
isESFAumgfhwU2LotkVRD6rgNl1QtMe3kCNWa9pCWQcYkxeI0IzA+JmFu2shVvoR
oL7eV4VCe1Af33z24E46+cY5grxNhHt/LyCnZKcitvCcrzXExUc5n6KngX0mMKgk
W7skZDwsnKzhyUV8wQJBAN2bQMeASQVOqdfqBdFgC/NPnKY2cuDi6h659QN1l+kg
X3ywdZ7KKftJo1G9l45SN9YpkyEd9zEO6PMFaufJvZUCQQDbtAWxk0i8BT3UTNWC
T/9bUQROPcGZagwwnRFByX7gpmfkf1ImIvbWVXSpX68/IjbjSkTw1nj/Yj1NwFZ0
nxeFAkEAzPhRpXVBlPgaXkvlz7AfvY+wW4hXHyyi0YK8XdPBi25XA5SPZiylQfjt
Z6iN6qSfYqYXoPT/c0/QJR+orvVJNQJBANhRPNXljVTK2GDCseoXd/ZiI5ohxg+W
UaA/1fDvQsRQM7TQA4NXI7BO/YmSk4rW1jIeOxjiIspY4MFAIh+7UL0CQFL6zTg6
wfeMlEZzvgqwCGoLuvTnqtvyg45z7pfcrg2cHdgCXIy9kErcjwGiu6BOevEA1qTW
Rk+bv0tknWvcz/s=
-----END PRIVATE KEY-----
`

var builder = require('xmlbuilder');
var SignedXml = require('xml-crypto').SignedXml;
var fs = require("fs");

function SXML() { //module.exports.SXML = function() {

    //Created the request XML as per the required format
    var xml = builder.create('Esign').att('AuthMode', '1').att('aspId', 'TNIC-001').att('kycId', '')
        .att('ekycIdType', 'A').att('responseSigType', "pkcs7")
        .att('responseUrl', 'https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1')
        .att('sc', 'Y').att('ts', '2020-05-19T11:28:01').att('txn', '999-ESIGN-DIVISION-2020-05-19T11:28:01')
        .att('ver', '2.1');
    //xml.ele("Docs").ele("InputHash",{'docInfo':'hello', 'hashAlgorithm':'SHA256', 'id':'1'},'5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e');
    xml.ele("Docs").ele("InputHash", {
        'docInfo': 'hello',
        'hashAlgorithm': 'SHA256',
        'id': '1'
    }, '5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e');

    // XML doc is ready for signing. Converted to String 
    var xmldoc = xml.toString({
        pretty: true
    });

    var sig = new SignedXml();
    //sig.addReference("/*",['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],'http://www.w3.org/2001/04/xmlenc#sha256','','','',true);

// NOTE: added http://www.w3.org/TR/2001/REC-xml-c14n-20010315 to the transformations list
    sig.addReference("/*", ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'], 'http://www.w3.org/2000/09/xmldsig#sha1', '', '', '', true);

    sig.signingKey = nicesign_pem; // fs.readFileSync("nicesign.pem");
    sig.canonicalizationAlgorithm = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
    sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
    sig.computeSignature(xmldoc.toString());

    return sig.getSignedXml();
}

console.log(SXML());

Output signed XML is:

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
<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"/><Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>1vWDVKN2jliWtO825GBmO4M3il4=</DigestValue></Reference></SignedInfo><SignatureValue>Pq2/YfGPOn6FuCVajV+EL3ZWZmIzXeiQtDVG6QawaEC1Vzp1xjDMkdmL9/o0w8P/bqTCuWBR3Yc8gTBlc9Busdwv3PEuWYggN/WTrP63FXGDDO2VxcejoQMsclIJ+C3BaO1zFRN11XbCt44xSUDtufUCwPE08HzQXFfeeOUl/jw=</SignatureValue></Signature></Esign>

and DigestValue is:

<DigestValue>1vWDVKN2jliWtO825GBmO4M3il4=</DigestValue>

if produced signed XML is pasted to https://tools.chilkat.io/xmlDsigVerify.cshtml it reports

Reference 1 digest is valid.

Pretty printed version of output signed xml for better readability

<Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
  <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"/>
          <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <DigestValue>1vWDVKN2jliWtO825GBmO4M3il4=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>Pq2/YfGPOn6FuCVajV+EL3ZWZmIzXeiQtDVG6QawaEC1Vzp1xjDMkdmL9/o0w8P/bqTCuWBR3Yc8gTBlc9Busdwv3PEuWYggN/WTrP63FXGDDO2VxcejoQMsclIJ+C3BaO1zFRN11XbCt44xSUDtufUCwPE08HzQXFfeeOUl/jw=</SignatureValue>
  </Signature>
</Esign>

So:

  1. "second opinion case" produced digest (without explicitly listing REC-xml-c14n-20010315 transform) which passed XmlDsigVerify's test.
  2. modified issue report code snippet (explicitly adding REC-xml-c14n-20010315 to the transformations list) produced exactly same digest as "second opinion case" and XmlDsigVerify had same opinion about digest value.

I have no idea whats actually wrong with xml-crypto <= 3.1.0 versions (didn't test with >= 6.x) but now there exists some test material for debugging and comparing with outputs of other tools.

I don't have any idea who (xml-crypto, xmlsec1 and/or XmlDsigVerify) is interpreting spec correctly.

edit: added pretty printed versions of signed output xmls for better readability

srd90 commented 7 months ago

Testing whether https://github.com/node-saml/xml-crypto/issues/212#issuecomment-1949310736 comments "second opinion case's" signed xml output verifies without errors with xml-crypto 1.5.3 (note: that XML has digestvalue that matches with content based on "third opinion" and that particular XML doesn't have explicitly listed REC-xml-c14n-20010315 transformation at transformations list:

/*
Relaed to https://github.com/node-saml/xml-crypto/issues/212

Test signature validation part of https://github.com/node-saml/xml-crypto/tree/v1.5.3
when transformations list contains only enveloped-signature

npm 6.14.18
node v14.21.3

{
  "name": "foo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "xml-crypto": "1.5.3",
    "xmlbuilder": "15.1.1"
  }
}
*/
var select = require('xml-crypto').xpath
    , dom = require('xmldom').DOMParser
    , SignedXml = require('xml-crypto').SignedXml
    , fs = require('fs')

// output of https://github.com/node-saml/xml-crypto/issues/212#issuecomment-1949310736
// comments "second opinion case" (of xmlsec1)
// Notice the absence of second transformation
var xml = `
  <Esign AuthMode="1" aspId="TNIC-001" kycId="" ekycIdType="A" responseSigType="pkcs7" responseUrl="https://nic-esigngateway.nic.in/eSign21/response?rs=localhost:8080/Esign_client/hello1" sc="Y" ts="2020-05-19T11:28:01" txn="999-ESIGN-DIVISION-2020-05-19T11:28:01" ver="2.1">
  <Docs>
    <InputHash docInfo="hello" hashAlgorithm="SHA256" id="1">5df2936623312f38371871bf5226e666c66318329d826bf7db544237096a837e</InputHash>
  </Docs>
<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/2000/09/xmldsig#sha1"/><DigestValue>1vWDVKN2jliWtO825GBmO4M3il4=</DigestValue></Reference></SignedInfo><SignatureValue>jfWA3qHH0fWFbZCqUHKlu1oc/vcfVdOV8yZMlqNVkCgwpP7m2HjDLt2j0NZJzFLd
BBLMXxc/Qb96MUra5g8bfOsIHjDW1Qh+GLovd+PO79TpZ4TPNMxJNy/bT82bXpjn
T1QCH3hNT82NQ0gZ1kgwkVmSJ/hNmQXgD4Sp+5YiBT4=</SignatureValue></Signature></Esign>
`

// https://raw.githubusercontent.com/node-saml/xml-crypto/21201723d2ca9bc11288f62cf72552b7d659b000/test/static/client_public.pem
var cert = `
-----BEGIN CERTIFICATE-----
MIIBxDCCAW6gAwIBAgIQxUSXFzWJYYtOZnmmuOMKkjANBgkqhkiG9w0BAQQFADAW
MRQwEgYDVQQDEwtSb290IEFnZW5jeTAeFw0wMzA3MDgxODQ3NTlaFw0zOTEyMzEy
MzU5NTlaMB8xHTAbBgNVBAMTFFdTRTJRdWlja1N0YXJ0Q2xpZW50MIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQC+L6aB9x928noY4+0QBsXnxkQE4quJl7c3PUPd
Vu7k9A02hRG481XIfWhrDY5i7OEB7KGW7qFJotLLeMec/UkKUwCgv3VvJrs2nE9x
O3SSWIdNzADukYh+Cxt+FUU6tUkDeqg7dqwivOXhuOTRyOI3HqbWTbumaLdc8juf
z2LhaQIDAQABo0swSTBHBgNVHQEEQDA+gBAS5AktBh0dTwCNYSHcFmRjoRgwFjEU
MBIGA1UEAxMLUm9vdCBBZ2VuY3mCEAY3bACqAGSKEc+41KpcNfQwDQYJKoZIhvcN
AQEEBQADQQAfIbnMPVYkNNfX1tG1F+qfLhHwJdfDUZuPyRPucWF5qkh6sSdWVBY5
sT/txBnVJGziyO8DPYdu2fPMER8ajJfl
-----END CERTIFICATE-----
`

var doc = new dom().parseFromString(xml)    

var signature = select(doc, "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0]
var sig = new SignedXml()
sig.keyInfoProvider = {
  getKey: function(keyInfo) {
    return cert;
  }
}
sig.loadSignature(signature)
var res = sig.checkSignature(xml)
if (!res) {
  console.log(sig.validationErrors)
} else {
  console.log("No validation errors.")
}

output is

No validation errors.

based on this it seems/feels as if this (from 1.5.3) would not be applied symmetrically (i.e. as if it would be applied to signature validation part only where-as other tools seem to be applying implicitly for digestvalue calculaton also or something like that): https://github.com/node-saml/xml-crypto/blob/d295ecca4d28d8827c761a636d69067ed8d36466/lib/signed-xml.js#L656-L667

cjbarth commented 7 months ago

@srd90 your sample code here gives a lot to go on, and I'm glad you were able to find this. @niladrinic , @CarlaMck77 , @cfficaurzua , if any of you would like to put up a PR to address this, that would be most welcome. I don't know when I'll have time to look into this, especially since this problem isn't affecting anything I'm working on. Even if you just put up a PR with a test that fails, that would be a huge help to getting things rolling.