如何针对X509Certificate2Collection链验证X509Certificate2

时间:2011-05-25 14:51:10

标签: .net single-sign-on x509certificate pkcs#7 saml-2.0

我正在编写一个SAML 2.0响应解析器来处理ASP.Net中的POST身份验证(在C#和MVC中,但这不太相关)。

所以我有一个.p7b文件要验证,可以读入X509Certificate2Collection和示例断言 - 基本64位编码的SAML响应。

理想情况下,我想使用内置的WSSecurityTokenSerializer,但that fails,所以我正在寻找一种有效的方式。

我正在直接阅读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。

我认为这是因为他们正在检查机器商店或可能在线(我不知道如何检查)。我想针对从X509Certificate2Collection文件中检索到的.p7b来检查它们 - 应该忽略机器上注册的证书,只检查.p7b证书。

似乎没有办法将X509Certificate2Collection传递给VerifyCheckSignature方法。

这是对SAML响应进行的正确检查吗?

有没有办法以我想要的方式使用.p7b证书?

1 个答案:

答案 0 :(得分:5)

您是否尝试过使用配置为在验证过程中搜索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时验证证书。