SignedXml.CheckSignature fails in .NET 4 but it works in .NET 3.5, 3 or 2

前端 未结 8 1126
无人共我
无人共我 2020-12-07 00:14

I have a response from a 3-rd party web service. I load an XmlDocument with that response.

  string txt = readStream.ReadToEnd();
  response = new XmlDocumen         


        
相关标签:
8条回答
  • 2020-12-07 00:47

    From .NET framework 4/4.5 the classes to work with x509 certificates and other security features are located in System.IdentityModel.dll. Search the respective classes in the namespace mentioned.

    0 讨论(0)
  • 2020-12-07 00:48
    public static Boolean VerifyDetachedSignature(string XmlSigFileName)
    {   
        // Create a new XML document.
        XmlDocument xmlDocument = new XmlDocument();
    
        // Load the passed XML file into the document.
        xmlDocument.Load(XmlSigFileName);
    
        // Find the "Signature" node and create a new XmlNodeList object.
        XmlNodeList nodeList = xmlDocument.GetElementsByTagName("Signature");
    
        // Create a new SignedXMl object.
        SignedXml signedXml = new SignedXml();
    
        // Load the signature node.
        signedXml.LoadXml((XmlElement)nodeList[0]);
    
        // Check the signature and return the result. 
        return signedXml.CheckSignature();
    }
    
    0 讨论(0)
  • 2020-12-07 00:52

    In order to check the signature on NET 4.0+ you have to change the context of your CanonicalizationMethod, therefore you have to initialize your signedXml object in the following way:

    XmlNodeList signatureNodeList = xmlDoc.GetElementsByTagName("Signature");
    
    SignedXml signedXml = new SignedXml((XmlElement)signatureNodeList[0]);
    
    signedXml.LoadXml((XmlElement)signatureNodeList[0]);
    
    //Then you proceed your check as usual
    
    0 讨论(0)
  • 2020-12-07 00:55

    This is a known issue. The Canonicalization implementation between .NET 3.5 and .NET 4.0 has changed.

    I don't know if this works on all XML signatures but the following works from the testing that I've done.

    Add the following C14N Transform class to your project:

    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);
      }
    }

    Register the class using the CryptoConfig.AddAlgorithm method.

    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.  

    That should do it.

    0 讨论(0)
  • 2020-12-07 00:55

    Try explicitly setting the Canonicalization method for the SignedInfo property of the SignedXml class.. It appears there has been a change in default behaviour here between .Net 2.0 and .Net 4.0

    signed.SignedInfo.CanonicalizationMethod = Signed.XmlDsigExcC14NTransformUrl;
    

    Reference:

    This answer

    0 讨论(0)
  • 2020-12-07 00:55
    // Assume the data to sign is in the data.xml file, load it, and
    
    // set up the signature object.
    XmlDocument doc = new XmlDocument();
    
    doc.Load(@"D:\Example.xml");
    SignedXml sig = new SignedXml(doc);
    
    // Make a random RSA key, and set it on the signature for signing.
    RSA key = new RSACryptoServiceProvider();
    
    sig.SigningKey = key;
    
    // Create a Reference to the containing document, add the enveloped
    // transform, and then add the Reference to the signature
    Reference refr = new Reference("");refr.AddTransform(new XmlDsigEnvelopedSignatureTransform());
    
    sig.AddReference(refr);
    
    // Compute the signature, add it to the XML document, and save
    sig.ComputeSignature();
    
    doc.DocumentElement.AppendChild(sig.GetXml());
    doc.Save("data-signed.xml");
    
    // Load the signed data
    
    //XmlDocument doc = new XmlDocument();
    doc.PreserveWhitespace = true;
    
    doc.Load("data-signed.xml");
    
    // Find the Signature element in the document
    XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
    
    nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
    XmlElement sigElt = (XmlElement)doc.SelectSingleNode("//dsig:Signature", nsm);
    
    // Load the signature for verification
    
    //SignedXml sig = new SignedXml(doc);
    
    sig.LoadXml(sigElt);
    
    // Verify the signature, assume the public key part of the
    
    // signing key is in the key variable
    if (sig.CheckSignature(key))
        Console.WriteLine("Signature verified");
    else
        Console.WriteLine("Signature not valid");
    
    0 讨论(0)
提交回复
热议问题