C#中XAdES签名时间戳摘要计算错误,EU DSS验证不通过
XAdES签名时间戳嵌入摘要验证失败的问题排查
我们开发的XAdES签名应用,签名本身可通过EU DSS验证器的正确性校验,但添加时间戳时,验证器提示嵌入的摘要不正确。已确认XML中嵌入的摘要与代码计算结果一致,推测是摘要计算方式存在错误,相关代码如下:
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)
问题根源
核心错误是时间戳的摘要计算对象不符合XAdES规范:
ETSI的XAdES标准(如EN 319 132-1)规定,签名时间戳(SignatureTimeStamp)需要对完整的<ds:Signature>节点执行规范化后计算摘要,以此绑定整个签名的完整性。而当前代码仅对<ds:SignatureValue>节点计算摘要,时间戳只绑定了签名值本身,不符合验证器的校验逻辑,因此提示摘要错误。
修正方案
修改代码,将摘要计算对象从<ds:SignatureValue>改为完整的<ds:Signature>节点:
XmlDocument d = new XmlDocument(); d.PreserveWhitespace=true; // 加载XML数据的代码(省略) XmlNamespaceManager nsm = new XmlNamespaceManager(d.NameTable); nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); // 修正:选择完整的ds:Signature节点 XmlNode signatureNode = d.SelectSingleNode("//ds:Signature", nsm); XmlDsigExcC14NTransform t = new XmlDsigExcC14NTransform(); t.LoadInput(signatureNode); // 传入完整签名节点执行规范化 byte[] digest = t.GetDigestedOutput(SHA256.Create()); // 后续时间戳请求代码保持不变 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; // 将dataToEmbed和algorithmUrlToEmbed嵌入XML
额外检查点
- 确认规范化算法:默认的
XmlDsigExcC14NTransform是不带注释的规范化(URL:http://www.w3.org/2001/10/xml-exc-c14n#),如果XAdES配置要求带注释的规范化,需改用new XmlDsigExcC14NTransform(true) - 保留空白设置:确保
d.PreserveWhitespace=true的配置正确,否则规范化结果会与验证器计算的不一致 - 算法匹配:确认时间戳请求的摘要算法(此处为SHA256)与签名算法一致,且时间戳服务器支持该算法
内容的提问来源于stack exchange,提问作者Fraggel
相关产品推荐
相关产品推荐

