xmldsigjs
xmldsigjs copied to clipboard
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>
`);
I'll share my code as well which works now and signature is validated using xmlsec1. I send in the certificates in PEM (CER) format (base64 with the BEGIN/END headers/footers).
const { XMLSerializer } = require('xmldom-alpha');
const xmldsigjs = require('xmldsigjs');
const { Crypto } = require('@peculiar/webcrypto');
const crypto = new Crypto();
xmldsigjs.Application.setEngine('NodeJS', crypto);
function preparePem(pem) {
return (
pem
// remove BEGIN/END
.replace(/-----(BEGIN|END)[\w\d\s]+-----/g, '')
// remove \r, \n
.replace(/[\r\n]/g, '')
);
}
function pem2der(pem) {
pem = preparePem(pem);
// convert base64 to ArrayBuffer
return new Uint8Array(Buffer.from(pem, 'base64')).buffer;
}
async function signXML(xmlString, publicKeyPem, privateKeyPem) {
// const fs = require('fs');
const hash = 'SHA-1';
const alg = {
name: 'RSASSA-PKCS1-v1_5',
hash,
publicExponent: new Uint8Array([1,0,1]),
modulusLength: 2048,
};
const keyDer = pem2der(privateKeyPem);
const key = await crypto.subtle.importKey('pkcs8', keyDer, alg, false, [
'sign'
]);
let xml = xmldsigjs.Parse(xmlString);
let digSigXml = new xmldsigjs.SignedXml();
const X509Data = new xmldsigjs.KeyInfoX509Data();
X509Data.AddSubjectName(process.env.SMP_QVALIA_CN);
digSigXml.XmlSignature.KeyInfo.Add(X509Data);
const signature = await digSigXml.Sign(
// Signing document
alg, // algorithm
key, // key
xml, // document
{
// options
references: [
{
hash,
transforms: ['enveloped']
},
],
x509: [preparePem(publicKeyPem)],
signingCertificate: preparePem(publicKeyPem)
}
);
// append signature
xml.documentElement.appendChild(signature.GetXml());
// serialize XML
const oSerializer = new XMLSerializer();
const sXML = oSerializer.serializeToString(xml);
// fs.writeFileSync("/home/anders/CodeStuff/signed3.xml", sXML.toString());
return sXML.toString();
}
So this is not a bug?
Your post made it sound like you solved your problem?
Ah, no, sorry if I'm being a pain... I just wanted to add my code in full incase I am missing something...
I meant that it is producing valid signatures IF I don't have any namespace prefix on the root element.
Is this one dea, or something someone is looking at?
As I understand it the signature validates with xmlsec1 but the other tool your using doesn’t like it.
this would require us to 1) have an example of a file it does like, 2) have access to the tool
We are also experiencing this issue. We validated using multiple tools, and having a namespace prefix in the root element causes validation issues.
Use an online validator like: https://tools.chilkat.io/xmlDsigVerify.cshtml
Steps to re-create The below example succeeds when using no root namespace prefixes
<InitSessionSignedRequest
xmlns="http://example.com/online/types/2021/10/01/0001"
xmlns:ns2="http://example.com/types/2021/10/01/0001"
xmlns:ns3="http://example.com/online/auth/request/2021/10/01/0001">
</InitSessionSignedRequest>
The below example fails when using a root prefix:
<ns3:InitSessionSignedRequest
xmlns="http://example.com/online/types/2021/10/01/0001"
xmlns:ns2="http://example.com/types/2021/10/01/0001"
xmlns:ns3="http://example.com/online/auth/request/2021/10/01/0001">
</ns3:InitSessionSignedRequest>
We tried multiple permutations and transforms, and the issue appears related to how the XML (and prefix) root is being handled in this library.