validationSAML断言上的签名

我有两个签名,一个在响应(validation),一个在嵌套的SAML断言(没有)。 这是我正在使用的精简代码:

foreach (XmlElement node in xmlDoc.SelectNodes("//*[local-name()='Signature']")) {// Verify this Signature block SignedXml signedXml = new SignedXml(node.ParentNode as XmlElement); signedXml.LoadXml(node); KeyInfoX509Data x509Data = signedXml.Signature.KeyInfo.OfType().First(); // Verify certificate X509Certificate2 cert = x509Data.Certificates[0] as X509Certificate2; log.Info(string.Format("Cert s/n: {0}", cert.SerialNumber)); VerifyX509Chain(cert);// Custom method // Check for approval X509Store store = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySerialNumber, cert.SerialNumber, true); Debug.Assert(collection.Count == 1);// Standing in for brevity // Verify signature signedXml.CheckSignature(cert, true); } 

为了完整起见,这里是XML的概述:

  ...  ...  ...  ...  ...  ...   

我也尝试过只签署的断言,但也失败了。 我究竟做错了什么? 为什么CheckSignature总是在SAML断言上失败?

编辑结果只有断言的断言是由Java生成的(OpenSAML)并且有更多的环节可以跳过。 请指教。

此代码使用Ultimate saml( http://www.componentpro.com/saml.net/ )validationSAML响应。 它有助于validation响应中的嵌套SAML断言签名。

 XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(samlResponseXmlToVerify); XmlDocument xmlDocumentMetadata = new XmlDocument(); xmlDocumentMetadata.Load(samlMetadataXmlToExtractCertData); // Load the SAML response from the XML document. Response samlResponse = new Response(xmlDocument.DocumentElement); // Is it signed? if (samlResponse.IsSigned()) { // Validate the SAML response with the certificate. if (!samlResponse.Validate(xmlDocumentMetadata.DocumentElement)) { throw new ApplicationException("SAML response signature is not valid."); } } 

有关更多详细信息,请参阅此在线示例代码: http : //www.componentpro.com/doc/saml/ComponentPro.Saml.SignableSamlObject.Validate().htm

我发现这个答案引用了另一个答案 (由同一个人 )并总结如下: .net实现是古怪的,Signature块必须是DocumentElement的子代。 发现这篇文章也以更好的方式解决了这个问题。

修改代码

 foreach (XmlElement node in xmlDoc.SelectNodes("//*[local-name()='Signature']")) {// Verify this Signature block // *** BEGIN: ADDED CODE *** XmlDocument doc = new XmlDocument(); doc.LoadXml(node.ParentNode.OuterXml); XmlElement signature = doc.SelectSingleNode("//*[local-name()='Signature']") as XmlElement; // This variable ^^^ is the same as node, just in doc instead of xmlDoc (important distinction) // *** END: ADDED CODE *** // Setup SignedXml signedXml = new SignedXml(node.ParentNode as XmlElement); signedXml.LoadXml(node); KeyInfoX509Data x509Data = signedXml.Signature.KeyInfo.OfType().First(); // Verify certificate ... 

不幸的是,这仍然不能解释Java生成的SAML。 需要更复杂,更少记录的东西来解释这一点。 我收到了一个新的Java生成的SAML令牌,它与给定的代码一起使用。 我使用的那个一定是有缺陷的。

我不确定为什么,但看起来SignedXml只能validation根文档元素中的签名。 我发现从现有XmlElement片段创建新XmlDocument的最快方法是使用ImportNode方法。

您更新的validation代码如下所示:

 foreach (XmlElement item in xmlDoc.SelectNodes("//*[local-name()='Signature']")) { var node = item; if (node.ParentNode != xmlDoc.DocumentElement) { var doc = new XmlDocument(); var parentNode = doc.ImportNode(item.ParentNode, true); doc.AppendChild(parentNode); node = (XmlElement) parentNode.SelectSingleNode("*[local-name()='Signature']"); } var signedXml = new SignedXml((XmlElement) node.ParentNode); signedXml.LoadXml(node); //TODO: validate } 

这大约是重新解析OuterXml速度的两倍,正如其他人基于我使用8kB SAML响应文档的测试所建议的那样。