我正在编写一个SAML 2.0响应解析器来处理ASP.Net中的POST身份验证(在C#和MVC中,但这不太相关)。
因此,我有一个.p7b
文件要验证,它可以读取为X509Certificate2Collection
和一个示例断言——一个基于64编码的SAML响应。
理想情况下,我想使用内置的WSSecurityTokenSerializer
,但失败了,所以我正在寻找一种有效的方法。
我直接阅读XML:
// get the base 64 encoded SAML
string samlAssertionRaw = GetFromHttpRequest();
// load a new XML document
var assertion = new XmlDocument { PreserveWhitespace = true };
assertion.LoadXml(samlAssertionRaw);
// use a namespace manager to avoid the worst of xpaths
var ns = new XmlNamespaceManager(assertion.NameTable);
ns.AddNamespace("samlp", @"urn:oasis:names:tc:SAML:2.0:protocol");
ns.AddNamespace("saml", @"urn:oasis:names:tc:SAML:2.0:assertion");
ns.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
// get the signature XML node
var signNode = assertion.SelectSingleNode(
"/samlp:Response/saml:Assertion/ds:Signature", ns);
// load the XML signature
var signedXml = new SignedXml(assertion.DocumentElement);
signedXml.LoadXml(signNode as XmlElement);
// get the certificate, basically:
// signedXml.KeyInfo.OfType<KeyInfoX509Data>().First().
// Certificates.OfType<X509Certificate2>().First()
// but with added checks
var certificate = GetFirstX509Certificate(signedXml);
// check the key and signature match
if (!signedXml.CheckSignature(certificate, true))
{
throw new SecurityException("Signature check failed.");
}
// go on and read the SAML attributes from the XML doc
这一切都有效,但它所做的只是检查SAML响应中的签名和X509Certificate2
公钥是否匹配。它不会以任何方式验证它来自谁,在接受SAML身份验证之前,我需要这样做。
检查SAML响应中的证书似乎有两种方法——我可以执行certificate.Verify()
,也可以使用签名signedXml.CheckSignature(certificate, false)
进行检查。
但是两者都返回false。
我想这是因为他们正在机器商店或网上进行检查(我不知道如何检查)。我想对照从.p7b
文件中检索到的X509Certificate2Collection
来检查它们——应该忽略在机器上注册的证书,只检查.p7b
证书。
似乎没有任何方法可以将X509Certificate2Collection
传递给Verify
或CheckSignature
方法。
这是对SAML响应进行的正确检查吗?
有什么方法可以按照我想要的方式使用.p7b
证书吗?
您是否尝试过在验证过程中使用配置为搜索证书的ExtraStore
的自定义X509Chain
。类似以下内容:
// Placeholder for the certificate to validate
var targetCertificate = new X509Certificate2();
// Placeholder for the extra collection of certificates to be used
var certificates = new X509Certificate2Collection();
var chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.ExtraStore.AddRange(certificates);
bool isValidCertificate = chain.Build(targetCertificate);
在该示例中,吊销检查也被禁用,但如果您可以在线或离线访问CRL,则可以启用它。
ExtraStore
应允许包含不在机器/用户存储中的中间证书。但是,受信任的根证书可能需要在机器或用户存储中,具体取决于在X509Chain
中指定的证书,否则会导致UntrustedRoot
失败。如果在机器或用户存储中甚至连根都不可用,您可以尝试遍历生成的链,并确保您遇到的唯一错误是由不受信任的根引起的,同时确保链根是您根据要验证的X509Certificate2Collection
所期望的。
或者,您可以创建自己的自定义X509CertificateValidator
来验证证书,只考虑提供的X509Certificate2Collection
。