我收到了第三方网络服务的回复。我加载了一个带有该响应的XmlDocument。
string txt = readStream.ReadToEnd();
response = new XmlDocument();
response.PreserveWhitespace = true;
response.LoadXml(txt);
return response;
现在我想验证响应是否使用证书签名。我在msdn上找到了VerifyXmlDoc(XmlDocument xmlDoc)
方法。
我知道这条消息是正确的。
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,则结果为false。 (我必须使用.NET 4)
关于如何解决这个问题的任何想法?
答案 0 :(得分: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);
}
}
&#13;
使用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.
&#13;
应该这样做。
答案 1 :(得分:1)
尝试为SignedXml类的SignedInfo属性显式设置Canonicalization方法。看起来.Net 2.0和.Net 4.0之间的默认行为发生了变化
signed.SignedInfo.CanonicalizationMethod = Signed.XmlDsigExcC14NTransformUrl;
参考:
答案 2 :(得分:1)
我有同样的问题,但这些答案都没有帮助我。在这种情况下,它的工作与否取决于我使用的操作系统,而不是.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".
我发现此Microsoft支持文章试图修复安全更新3141780引入的错误: 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
答案 3 :(得分:0)
// 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");
答案 4 :(得分:0)
从.NET framework 4 / 4.5开始,使用x509证书和其他安全功能的类位于System.IdentityModel.dll中。搜索提到的命名空间中的相应类。
答案 5 :(得分:0)
我解决了这个问题,从Signature标签添加相同的命名空间到SignedInfo。 像这样:
在:
在:
答案 6 :(得分:0)
为了检查NET 4.0+上的签名,您必须更改CanonicalizationMethod的上下文,因此您必须按以下方式初始化signedXml对象:
loadTrade(intent.getExtras().getString("ID"));
答案 7 :(得分:-2)
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();
}