We have an application that is creating XAdES signatures. The signatures are validated correctly by the EU DSS validator. Unfortunately, when trying to add timestamps, the validator indicates that the imprinted digest is incorrect.
We use the following code for calculating the digest:
XmlDocument d = new XmlDocument();
d.PreserveWhitespace=true;
// Left out code to load actual XML data
// Make sure we can find the signature in the right namespace
XmlNamespaceManager nsm = new XmlNamespaceManager(d.NameTable);
nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
// Find the SignatureValue node (we only have one, but selection could be done cleaner)
XmlNodeList n = d.SelectNodes("//ds:SignatureValue", nsm);
// ETSI prescribes the use of C14N
XmlDsigExcC14NTransform t = new XmlDsigExcC14NTransform();
t.LoadInput(n);
// We use SHA256 hashing on the canonicalized data
byte[] digest = t.GetDigestedOutput(SHA256.Create());
// The value of the digest variable is being timestamped using BouncyCastle.netcore library
TimeStampRequest request = requestGenerator.Generate(a, digest, BigInteger.ValueOf(100));
using HttpClient client = _hcf.CreateClient();
ByteArrayContent content = new ByteArrayContent(request.GetEncoded());
HttpResponseMessage msg = await client.PostAsync(_config["AppSettings:TimeStampServer"], content);
TimeStampResponse response = new TimeStampResponse(await msg.Content.ReadAsByteArrayAsync());
byte[] dataToEmbed = response.TimeStampToken.GetEncoded();
string algorithmUrlToEmbed = t.Algorithm;
// the content of dataToEmbed is embedded into the XML
// together with the url of the canonicalization (algorithmUrlToEmbed)
What are we doing wrong that the EU DSS validator states that the imprinted digest of the timestamp token is wrong. We checked the generated XML, the imprinted digest is equal to the digest we calculated, so probably we are calculating the digest incorrectly.
We found the answer is to not directly add the nodelist to the XmlDsigExcC14NTransform, but to load the nodelist into a new XML document object and load that into the transform object.
So instead of
// Find the SignatureValue node (we only have one, but selection could be done cleaner)
XmlNodeList n = d.SelectNodes("//ds:SignatureValue", nsm);
// ETSI prescribes the use of C14N
XmlDsigExcC14NTransform t = new XmlDsigExcC14NTransform();
t.LoadInput(n);
we can do
// Find the SignatureValue node (we only have one, but selection could be done cleaner)
XmlNodeList n = d.SelectNodes("//ds:SignatureValue", nsm);
// ETSI prescribes the use of C14N
XmlDsigExcC14NTransform t = new XmlDsigExcC14NTransform();
XmlDocument doc = new XmlDocument();
doc.LoadXml(n[0].OuterXml);
t.LoadInput(doc);
As we hardcoded the use of the first element of the nodelist, this is not yet a solution for multiple elements, but for our use case this sufficient.