我在这里查看了有关此问题的其他帖子,但这些帖子似乎都没有解决我的情况。
我一直在尝试验证上周的SAML断言,并且我有2个客户端向我发送了SAML,但我无法对其进行验证。
主要过程是我们得到一个base64编码的断言,然后我对其进行解码。使用PreserveWhitespace = true将其加载到XmlDocment中。
验证方法是
public static bool Verify(X509Certificate2 cert, XmlElement xmlElement, SignedXml signedXml)
{
bool flag;
try
{
KeyInfo keyInfo = new KeyInfo();
var clause = new KeyInfoX509Data(cert);
keyInfo.AddClause(clause);
XmlElement signatureElement = GetSignatureElement(xmlElement);
if (signatureElement == null)
{
string message = "The XML does not contain a signature.";
throw new SAMLSignatureException(message);
}
signedXml.LoadXml(signatureElement);
if (keyInfo != null)
{
signedXml.KeyInfo = keyInfo;
}
SetSigningKeyFromKeyInfo(signedXml);
flag = signedXml.CheckSignature(cert.PublicKey.Key);
}
catch (Exception exception)
{
throw new SAMLSignatureException("Failed to verify the XML signature.", exception);
}
return flag;
}
private static void SetSigningKeyFromKeyInfo(SignedXml signedXml)
{
IEnumerator enumerator = signedXml.KeyInfo.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current is KeyInfoX509Data)
{
var current = (KeyInfoX509Data) enumerator.Current;
if (current.Certificates.Count != 0)
{
var certificate = (X509Certificate) current.Certificates[0];
var certificate2 = new X509Certificate2(certificate);
AsymmetricAlgorithm key = certificate2.PublicKey.Key;
signedXml.SigningKey = key;
return;
}
}
else
{
if (enumerator.Current is RSAKeyValue)
{
var value2 = (RSAKeyValue) enumerator.Current;
signedXml.SigningKey = value2.Key;
return;
}
if (enumerator.Current is DSAKeyValue)
{
var value3 = (DSAKeyValue) enumerator.Current;
signedXml.SigningKey = value3.Key;
return;
}
}
}
throw new SAMLSignatureException("No signing key could be found in the key info.");
}
我有从Web.Config中读取的客户端证书(其存储为base64编码的字符串),xmlelement是签名元素,signedXml是使用新SignedXml(xmlElement)创建的SignedXml对象。
两个客户都将通过checksignature返回false,但是当我使用自己的证书创建自己的签名saml时,它将返回true。
我在这里想念什么?
编辑:是的两个客户端都在Java上,我发布了SetSigningKeyFromKeyInfo方法
最佳答案
过去,我处理签名XML的工作很多。我只能说那是一场噩梦。基本上,当您签署XML时,它会经历一个称为规范化(C14N)的过程。它需要将XML文本转换为可以签名的字节流。 XML C14N标准中的空格和 namespace 处理等等很难理解,甚至很难实现。甚至有多种类型的C14N。
.NET实现对接受的内容非常有选择性。您的其他实现很有可能无法以与.NET完全相同的方式工作。确实,这是非常可悲的。例如,如果您可以在签名之前从源XML中消除空格和 namespace ,则可能会有所帮助。另外,如果您可以确保两个实现都使用相同的C14N设置。
否则,大量调试将等着您。您可以调试框架,或通过反射手动调用其内部方法,以查看其如何计算XML片段和签名。并与其他实现相同。基本上,您需要查看两种情况下签名的确切字节流。这是签名之前转换的最后一步。如果这些字节流匹配,那么根据我的经验,您将对RSA签名部分没有任何问题。如果与您的情况不符,至少您会发现问题出在哪里。