Alaa Eddine Cherif
Alaa Eddine Cherif

Reputation: 195

Signing XML and validating it returns invalid signature

I'm using xml-crypto to sign an XML document in order to communicate with an API. This is the code that I use to sign it (it's pretty close to the tutorial in the readme file of the library).

var sig = new SignedXml({ privateKey: this.privateKey, publicCert: this.publicCert });
sig.addReference({
  xpath: "//*[local-name(.)='Object']",
  digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256',
  transforms: ['http://www.w3.org/2001/10/xml-exc-c14n#'],
});
sig.canonicalizationAlgorithm = 'http://www.w3.org/2001/10/xml-exc-c14n#';
sig.signatureAlgorithm = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
sig.computeSignature(xml);

const signedXml= sig.getSignedXml();

However when I try to verify the signature, the checkSignature method always returns false (as in signature is invalid)

I use the following code to verify the signature.

const signed = new SignedXml({
  publicCert: dip.publicCert,
});

const signature = signedXml.match(/<Signature[\s\S]*?<\/Signature>/)?.[0]!;
signed.loadSignature(signature);
console.log(signed.checkSignature(signedXml))

The weird thing is, whenever I change the xpath of the reference to not be the root element (e.g. //*[local-name(.)='dip'] instead of //*[local-name(.)='Object'] the validation works.

Also the API requires an enveloping signature which I do not thing is available out of the box in xml-crypto.

My plan is to manipulate the XML manually in order for the Object to be nested inside the Signature element.

This is what the specifications states:

The signature is therefore integrated into the file to be transmitted by wrapping the signature around the data XML. The digital signature is created by the user with his private key, which was also used to generate the certificate for the activation request. It proves the authorship of the customer system and ensures the integrity of the mass data delivery. During signing, the dip element is attached as a child node of the ds:Object and signed together with it. In this way, the XML file shown below is created from the above example XML file with the unsigned dip element by adding the enveloping signature.

This is an example of how the XML should look like from the API specifications:

<?xml version="1.0" encoding="UTF-8"?>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-
MGF1"/>
<ds:Reference URI="#object">
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue><!-- base64-codierter Digest-value einfügen --></ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue><!-- base64-codierte Signatur einfügen --></ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509SubjectName><!-- Subject Name einfügen --></ds:X509SubjectName>
<ds:X509Certificate><!-- base64-codiertes Zertifikat einfügen --></ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
<ds:Object Id="object">
<dip xmlns="http://itzbund.de/ozg/bzst/post/dip/v1/" version="1.0">
<header environment="TEST">
...
</header>
<body>
...
</body>
</dip>

I've included in this Gist the signed and unsigned XML documents.

What am I doing wrong and is there a way to work around this. Thanks!

Upvotes: 0

Views: 97

Answers (0)

Related Questions