我有一个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)
如何解决这个问题的任何想法?
这是一个已知的问题。 .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.
这应该这样做。
尝试明确设置的规范化方法的SignedXml类的SignedInfo属性。它似乎有一直在这里的.Net 2.0和.Net 4.0之间默认行为的变化
signed.SignedInfo.CanonicalizationMethod = Signed.XmlDsigExcC14NTransformUrl;
参考:
这个答案
我有同样的问题,但没有这些答案的帮助了我。 在这种情况下,它的工作原理,或者不考虑我所用,而不是在.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
// 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");
从.NET框架4 / 4.5类与X509证书等安全功能都位于System.IdentityModel.dll工作。 搜索中提到的命名空间中的各个类别。
我解决了这个问题,将自签字标签的SignedInfo相同的命名空间。 像这样:
之前:
后:
为了检查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
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();
}