【问题标题】:Incorrect reference element signature XML C#不正确的参考元素签名 XML C#
【发布时间】:2016-02-14 21:55:42
【问题描述】:

我需要实现 EBICS 协议,特别是 HPB 请求,我需要签署我的 XML 文件:

    <?xml version="1.0" encoding="UTF-8"?>
<ebicsNoPubKeyDigestsRequest xmlns="http://www.ebics.org/H003" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ebics.org/H003 http://www.ebics.org/H003/ebics_keymgmt_request.xsd" Version="H003" Revision="1">
  <header authenticate="true">
    <static>
      <HostID>EBIXQUAL</HostID>
      <Nonce>234AB2340FD2C23035764578FF3091C1</Nonce>
      <Timestamp>2015-11-13T10:32:30.123Z</Timestamp>
      <PartnerID>AD598</PartnerID>
      <UserID>EF056</UserID>
      <OrderDetails>
        <OrderType>HPB</OrderType>
        <OrderAttribute>DZHNN</OrderAttribute>
      </OrderDetails>
      <SecurityMedium>0000</SecurityMedium>
    </static>
    <mutable />
  </header>
</ebicsNoPubKeyDigestsRequest>

所以我需要在元素上签名

authenticate="true"

为了用 C# 签署我的文档,我编写了以下代码:

XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = false;
        xmlDoc.Load("hpbtest.xml");
        RSA Key = new GestionCertificat("CN=XML_ENC_TEST_CERT4").getClePrivee();
        // Create a SignedXml object.
        SignedXml signedXml = new SignedXml(xmlDoc);
        // Add the key to the SignedXml document.
        signedXml.SigningKey = Key;
        // Create a reference to be signed.
        Reference reference = new Reference();
        reference.Uri = "#xpointer(//*[@authenticate='true'])";
        // Add an enveloped transformation to the reference.
        XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
        reference.AddTransform(env);
        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);
        // Compute the signature.
        signedXml.ComputeSignature();
        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml();
        // Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
        xmlDoc.Save("hpbtest.xml");

但是当我尝试签名时,我在线收到此错误

signedXml.ComputeSignature()

不正确的参考元素

你能帮我解决我的问题吗?

提前谢谢你!

托马斯!

【问题讨论】:

    标签: c# xml signature xml-signature


    【解决方案1】:

    我通过 SignedXml 和 Reference 类对 XPointer 操作进行了逆向工程......我可以在单独的答案中为您提供所有详细信息,但我现在得出的结论是,您只能有两种类型的查询:

    #xpointer(/)
    

    这是有效的,因为它是明确检查的,并且

    #xpointer(id(
    

    这再次被明确地(使用 string.StartsWith)检查。

    因此,正如您在评论中指出的那样,实现此目的的唯一方法似乎是扩展 SignedXml 类并覆盖 GetIdElement 方法,如下所示:

    public class CustomSignedXml : SignedXml
    {
        XmlDocument xmlDocumentToSign;
    
        public CustomSignedXml(XmlDocument xmlDocument) : base(xmlDocument)
        {
            xmlDocumentToSign = xmlDocument;
        }
    
        public override XmlElement GetIdElement(XmlDocument document, string idValue)
        {
            XmlElement matchingElement = null;
            try
            {
                matchingElement = base.GetIdElement(document, idValue);
            }
            catch (Exception idElementException)
            {
                Trace.TraceError(idElementException.ToString());
            }
    
            if (matchingElement == null)
            {
                // at this point, idValue = xpointer(//*[@authenticate='true'])
                string customXPath = idValue.TrimEnd(')');
                customXPath = customXPath.Substring(customXPath.IndexOf('(') + 1);
                matchingElement = xmlDocumentToSign.SelectSingleNode(customXPath) as XmlElement;
            }
    
            return matchingElement;
        }
    }
    

    然后在消费者代码中,只需将 SignedXml 更改为 CustomSignedXml:

    CustomSignedXml signedXml = new CustomSignedXml(xmlDoc);
    

    【讨论】:

    • Ebics 协议不接受标头元素上的 id 属性,因此我无法使用您的解决方案
    • 很抱歉,因为我主要是从我的研究中得到的最深层次的问题和唯一的解决方法。
    • 你认为我可以用 #xpointer(//*[@authenticate='true')] 覆盖 GetIdElement 来选择好的节点吗?但我不知道我在哪里可以做到这一点
    • 是的。 SignedXml 类不是密封的,方法是虚拟的。扩展 SignedXml 类并覆盖此方法,然后您可以在 try catch 块中测试基本方法,如果它失败或返回 null,您可以找到 xml 元素并返回它
    • 如果你有一个小时,我可以将其添加到我的答案中
    猜你喜欢
    • 1970-01-01
    • 2011-04-28
    • 2017-05-24
    • 2017-07-15
    • 1970-01-01
    • 1970-01-01
    • 2015-01-26
    • 2020-08-08
    相关资源
    最近更新 更多