接收方无法验证签名的 XML 消息

Posted

技术标签:

【中文标题】接收方无法验证签名的 XML 消息【英文标题】:Receiving side failing to validate signed XML message 【发布时间】:2020-06-28 21:26:35 【问题描述】:

我正在尝试根据为我们的测试应用程序提供的规格表使用 C# 签署一些 XML。我们必须:

    规范化消息。 使用摘要算法创建整个消息的摘要。 将摘要添加到签名信息元素。 规范化签名信息。 将私钥和规范化的签名信息输入到指定的签名算法中,生成数字签名。 将生成的数字签名添加到签名元素。

这是我目前拥有的。

public static XmlElement Sign(XmlDocument msgDoc)

    XmlDsigExcC14NTransform transform = new XmlDsigExcC14NTransform();
    transform.LoadInput(msgDoc);
    msgDoc.Load(transform.GetOutput() as Stream);

    var signedXml = new SignedXml(msgDoc)
    
        SigningKey = Certificate.GetRSAPrivateKey(),
    ;

    signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

    var reference = new Reference();
    reference.AddTransform(new XmlDsigEnvelopedSignatureTransform(true));
    reference.AddTransform(new XmlDsigC14N11Transform()); // Custom transform
    reference.Uri = string.Empty;
    reference.DigestMethod = SignedXml.XmlDsigSHA256Url;

    signedXml.SignedInfo.AddReference(reference);

    KeyInfo keyInfo = new KeyInfo();
    var keyInfoData = new KeyInfoX509Data();
    keyInfoData.AddIssuerSerial(CertManager.Certificate.Issuer, CertManager.Certificate.SerialNumber);
    keyInfoData.AddSubjectName(CertManager.Certificate.Subject);
    keyInfo.AddClause(keyInfoData);
    signedXml.KeyInfo = keyInfo;

    signedXml.ComputeSignature();
    XmlElement signature = signedXml.GetXml();

    // This part until the return was done to ensure we get the 'ds' prefix.
    // Code taken from: https://***.com/questions/30579938/generate-digital-signature-but-with-a-specific-namespace-prefix-ds
    SetPrefix("ds", signature);
    signedXml.LoadXml(signature);
    signedXml.SignedInfo.References.Clear();
    signedXml.ComputeSignature();        
    ReplaceSignature(signature, Convert.ToBase64String(signedXml.SignatureValue));
    XmlNode signatureElement = msgDoc.ImportNode(signature, true);

    return msgDoc.DocumentElement.InsertAfter(msgDoc.ImportNode(signature, true), msgDoc.DocumentElement.FirstChild) as XmlElement;

摘要算法为:http://www.w3.org/2001/04/xmlenc#sha256

规范化算法为:http://www.w3.org/2001/10/xml-exc-c14n#

我们使用了两个转换:http://www.w3.org/2000/09/xmldsig#enveloped-signature 和 http://www.w3.org/2006/12/xml-c14n11

我已经在另一端启用了跟踪,它应该验证消息,这似乎是跟踪日志中唯一出现故障的地方:

[SignedXml#0071d445, VerificationFailure] 验证检查 SignedInfo 失败。

我已确保签名过程中使用的Certificate 是我的私有证书,而另一方使用公共证书进行验证过程。

我还缺少什么?

编辑:

我们能够验证我们从他们那里收到的消息。我无法提供他们如何验证消息的任何代码,因为它没有提供给我们。

这是我们发送的示例:

<Message xmlns="urn:tch">
  <AppHdr>
    <head:Fr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
      <head:ID>
        <head:MemberId>1234245</head:MemberId>
      </head:ID>
    </head:Fr>
    <head:To xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
      <head:ID>
        <head:MemberId>123345345</head:MemberId>
      </head:ID>
    <head:Date xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">2020-03-16T22:03:24</head:Date>
    <head:Sgntr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
          <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
          <ds:Reference URI="">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
              <ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>fV61VLaSYGyW+G+LxZaLfGdOlAVmpJvusoJ792IKblw=</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>xlg1Q4hdQoCo+x4rJKWn1UwLwdshonx0dg5Z0bIAsFuBWOJGyVescQBFEZEbUHcgLq2TQZT6PBhH3F2RR4aYTnc9IY0mHRq5rJEpVfXnQZdwCw7SIhkMMIOi5rAgQ5gdLmQlbLWFm8V4+1DTE7QWiCALEkarJQcdU4n9E2rGrSM48H1NFHHC+m8J5eHcGFyRcBwSF712ihGDNvweGhwneR4JeGxyQ3Dc1pSkzkr0oOJDY0vgwIuMZIMvl6Fh98D3QByDadZqFah88uv+TWZy01B9rdfhgCP7gdeiP9fof90jnitQ4c/3XksjieLbWQxWmQ1TPoRQswDuXf731T6kmw==</ds:SignatureValue>
        <ds:KeyInfo>
          <ds:X509Data>
            <ds:X509IssuerSerial>
              <ds:X509IssuerName>CN=ABC, DC=AAA, DC=BBB, DC=CCC</ds:X509IssuerName>
              <ds:X509SerialNumber>75822323454364025267732697561489775234425345</ds:X509SerialNumber>
            </ds:X509IssuerSerial>
            <ds:X509SubjectName>E=something@somewhere.com, CN=ABC.com, OU=Internet Services, O=AAA, L=Someplace, S=somewhere, C=US</ds:X509SubjectName>
          </ds:X509Data>
        </ds:KeyInfo>
      </ds:Signature>
    </head:Sgntr>
  </AppHdr>
  <TestMessage>
    <mr:zzzz.002.001.01 xmlns:mr="urn:iso:std:iso:20022:tech:xsd:zzzz.002.001.01">
      <mr:Ref>
        <mr:Ref>20200316220315134567890122203156779</mr:Ref>
      </mr:Ref>
  </TestMessage>
</Message>

编辑:如果有人使用上述信息创建示例进行签名,我将接受答案。

【问题讨论】:

接收方可以验证你的证书链吗?他们的受信任证书存储中是否有颁发者证书(***证书颁发机构)? @OguzOzgul 是的。 该错误表示加密选项与解密选项不同。因此,您必须比较两端的选项并让他们同意。只看加密代码并没有帮助。 Fiddler 将显示发送端使用的选项,这将验证您是否发送了有效的签名 xml,但不会显示接收选项。 @jdweng 不知道你的意思 @Jimenemex 1. 你能验证你的签名吗? 2. 能否提供验证对方签名的代码? 3. 您能否在帖子中添加一个由您的Sign 方法签名的示例 XML 文件? 【参考方案1】:

为了修复接收方,我们将 X509SubjectName 节点中的 S= 替换为 ST=。

【讨论】:

以上是关于接收方无法验证签名的 XML 消息的主要内容,如果未能解决你的问题,请参考以下文章

签名加密证书的基本原理和理解

请问这个签名 java 应该怎么解析

签名验证前发件人证书已过期

如何将公钥从字符串类型转换为 PEM

Android Studio 之签名

openssl生成签名与验证签名