Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
niladrinic opened this issue May 20, 2020 · 8 comments

Comments

@niladrinic
Copy link

niladrinic commented May 20, 2020

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
Copy link
Contributor

djaqua commented May 8, 2023

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

@cjbarth
Copy link
Contributor

cjbarth commented May 29, 2023

@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
Copy link

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
Copy link

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
Copy link
Contributor

cjbarth commented Feb 15, 2024

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.

@cjbarth cjbarth reopened this Feb 15, 2024
@srd90
Copy link

srd90 commented Feb 16, 2024

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 #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
Copy link

srd90 commented Feb 16, 2024

Testing whether #212 (comment) 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):

/**
* DigestMethods take an octet stream rather than a node set. If the output of the last transform is a node set, we
* need to canonicalize the node set to an octet stream using non-exclusive canonicalization. If there are no
* transforms, we need to canonicalize because URI dereferencing for a same-document reference will return a node-set.
* See:
* https://www.w3.org/TR/xmldsig-core1/#sec-DigestMethod
* https://www.w3.org/TR/xmldsig-core1/#sec-ReferenceProcessingModel
* https://www.w3.org/TR/xmldsig-core1/#sec-Same-Document
*/
if (transforms.length === 0 || transforms[transforms.length - 1] === "http://www.w3.org/2000/09/xmldsig#enveloped-signature") {
transforms.push("http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
}

@cjbarth
Copy link
Contributor

cjbarth commented Feb 17, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants