SignedXml.CheckSignature未能在.NET 4中,但它在.NET 3.5,3或2

2019-07-04 06:20发布

我有一个3第三方Web服务的响应。 我加载与该响应一个如下。

  string txt = readStream.ReadToEnd();
  response = new XmlDocument();
  response.PreserveWhitespace = true;
  response.LoadXml(txt);   
  return response;

现在我想验证使用证书的阶跃响应签署。 我有一个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;

    }

如果我在我的项目的目标框架设置为.NET 3.5或.NET 3,或.NET 2它的伟大工程。 结果是真实的。 但是,如果我改变目标框架到.NET 4的结果是假的。 (我不得不使用.NET 4)

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

Answer 1:

这是一个已知的问题。 .NET 3.5和.NET 4.0的规范化实现已更改。

我不知道这是否适用于所有的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); } } 

注册使用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. 

这应该这样做。



Answer 2:

尝试明确设置的规范化方法的SignedXml类的SignedInfo属性。它似乎有一直在这里的.Net 2.0和.Net 4.0之间默认行为的变化

signed.SignedInfo.CanonicalizationMethod = Signed.XmlDsigExcC14NTransformUrl;

参考:

这个答案



Answer 3:

我有同样的问题,但没有这些答案的帮助了我。 在这种情况下,它的工作原理,或者不考虑我所用,而不是在.NET版本手术系统。

我已经在app.config中添加该代码,看看发生了什么事背后启用SignedXML日志:

<system.diagnostics>
        <sources>
            <source name="System.Security.Cryptography.Xml.SignedXml" switchName="XmlDsigLogSwitch">
                <listeners>
                    <add name="logFile" />
                </listeners>
            </source>
        </sources>
        <switches>
            <add name="XmlDsigLogSwitch" value="Verbose" />
        </switches>
        <sharedListeners>
            <add name="logFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="XmlDsigLog.txt"/>
        </sharedListeners>
        <trace autoflush="true">
            <listeners>
                <add name="logFile" />
            </listeners>
        </trace>
    </system.diagnostics>

它写了这一行:

System.Security.Cryptography.Xml.SignedXml Information: 17 : [SignedXml#033ec00f, UnsafeTransformMethod] Canonicalization method "http://www.w3.org/TR/1999/REC-xpath-19991116" is not on the safe list. Safe canonicalization methods are: "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments", "http://www.w3.org/2001/10/xml-exc-c14n#", "http://www.w3.org/2001/10/xml-exc-c14n#WithComments", "http://www.w3.org/2000/09/xmldsig#enveloped-signature", "http://www.w3.org/2000/09/xmldsig#base64", "urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform", "http://www.w3.org/2002/07/decrypt#XML".

我发现它试图以修复安全更新3141780引入了一个错误此Microsoft支持文章: https://support.microsoft.com/en-us/kb/3148821

成文章,在方案2节,有2个解决方案,我将固定相关的XPath的注册表键变换问题的方法:HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft.NETFramework \安全\ SafeTransformMethods @ XmlDsigXPathTransform = HTTP://www.w3 .ORG / TR / 1999 / REC-XPath的19991116



Answer 4:

// 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");


Answer 5:

从.NET框架4 / 4.5类与X509证书等安全功能都位于System.IdentityModel.dll工作。 搜索中提到的命名空间中的各个类别。



Answer 6:

我解决了这个问题,将自签字标签的SignedInfo相同的命名空间。 像这样:

之前:

后:



Answer 7:

为了检查4.0+你必须改变你的CanonicalizationMethod的背景下网上的签名,因此,你必须初始化下列方式您signedXml对象:

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

SignedXml signedXml = new SignedXml((XmlElement)signatureNodeList[0]);

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

//Then you proceed your check as usual


Answer 8:

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


文章来源: SignedXml.CheckSignature fails in .NET 4 but it works in .NET 3.5, 3 or 2