SignedXml.CheckSignature在.NET 4中失败,但它适用于.NET 3.5,3或2

use*_*548 34 c# security certificate signature signedxml

我收到了第三方网络服务的回复.我加载了一个带有该响应的XmlDocument.

  string txt = readStream.ReadToEnd();
  response = new XmlDocument();
  response.PreserveWhitespace = true;
  response.LoadXml(txt);   
  return response;
Run Code Online (Sandbox Code Playgroud)

现在我想验证响应是否使用证书签名.我有一个VerifyXmlDoc(XmlDocument xmlDoc)我在msdn上找到的方法.

我知道这条消息是正确的.

    public bool VerifyXmlDoc(XmlDocument xmlDoc)
    {

        SignedXml signed = new SignedXml(xmlDoc);

        XmlNodeList signatureNodeList = xmlDoc.GetElementsByTagName("Signature");


        signed.LoadXml((XmlElement)signatureNodeList[0]);

        X509Certificate2 serviceCertificate = null;
        foreach (KeyInfoClause clause in signed.KeyInfo)
        {
            if (clause is KeyInfoX509Data)
            {
                if (((KeyInfoX509Data)clause).Certificates.Count > 0)
                {
                    serviceCertificate = (X509Certificate2)((KeyInfoX509Data)clause).Certificates[0];
                }
            }
        }


        bool result = signed.CheckSignature(serviceCertificate, true);
        return result;

    }
Run Code Online (Sandbox Code Playgroud)

如果我将我的项目的目标框架设置为.NET 3.5或.NET 3,或.NET 2,它的工作原理很棒.结果是真的.但是如果我将目标框架更改为.NET 4,则结果为false.(我必须使用.NET 4)

关于如何解决这个问题的任何想法?

小智 7

这是一个已知的问题..NET 3.5和.NET 4.0之间的Canonicalization实现已更改.

我不知道这是否适用于所有XML签名,但以下工作来自我已经完成的测试.

将以下C14N Transform类添加到项目中:

public class MyXmlDsigC14NTransform: XmlDsigC14NTransform {
  static XmlDocument _document;
  public static XmlDocument document {
    set {
      _document = value;
    }
  }

  public MyXmlDsigC14NTransform() {}

  public override Object GetOutput() {
    return base.GetOutput();
  }

  public override void LoadInnerXml(XmlNodeList nodeList) {
    base.LoadInnerXml(nodeList);
  }

  protected override XmlNodeList GetInnerXml() {
    XmlNodeList nodeList = base.GetInnerXml();
    return nodeList;
  }

  public XmlElement GetXml() {
    return base.GetXml();
  }

  public override void LoadInput(Object obj) {
    int n;
    bool fDefaultNS = true;

    XmlElement element = ((XmlDocument) obj).DocumentElement;

    if (element.Name.Contains("SignedInfo")) {
      XmlNodeList DigestValue = element.GetElementsByTagName("DigestValue", element.NamespaceURI);
      string strHash = DigestValue[0].InnerText;
      XmlNodeList nodeList = _document.GetElementsByTagName(element.Name);

      for (n = 0; n < nodeList.Count; n++) {
        XmlNodeList DigestValue2 = ((XmlElement) nodeList[n]).GetElementsByTagName("DigestValue", ((XmlElement) nodeList[n]).NamespaceURI);
        string strHash2 = DigestValue2[0].InnerText;
        if (strHash == strHash2) break;
      }

      XmlNode node = nodeList[n];

      while (node.ParentNode != null) {
        XmlAttributeCollection attrColl = node.ParentNode.Attributes;
        if (attrColl != null) {
          for (n = 0; n < attrColl.Count; n++) {
            XmlAttribute attr = attrColl[n];
            if (attr.Prefix == "xmlns") {
              element.SetAttribute(attr.Name, attr.Value);
            } else if (attr.Name == "xmlns") {
              if (fDefaultNS) {
                element.SetAttribute(attr.Name, attr.Value);
                fDefaultNS = false;
              }
            }
          }
        }

        node = node.ParentNode;
      }
    }

    base.LoadInput(obj);
  }
}
Run Code Online (Sandbox Code Playgroud)

使用CryptoConfig.AddAlgorithm方法注册该类.

CryptoConfig.AddAlgorithm(typeof(MyXmlDsigC14NTransform), "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"); 

var message = new XmlDocument();
message.PreserveWhitespace = true;
message.Load("XmlSig.xml");

MyXmlDsigC14NTransform.document = message; // The transform class needs the xml document

// Validate signature as normal.  
Run Code Online (Sandbox Code Playgroud)

应该这样做.


Ono*_*ots 1

尝试为 SignedXml 类的 SignedInfo 属性显式设置 Canonicalization 方法。.Net 2.0 和 .Net 4.0 之间的默认行为似乎发生了变化

signed.SignedInfo.CanonicalizationMethod = Signed.XmlDsigExcC14NTransformUrl;
Run Code Online (Sandbox Code Playgroud)

参考:

这个答案