如何在 C# 中验证来自特定根 CA 的证书链

Tha*_*nas 8 c# security ca x509certificate

我有一个如下所示的证书链:root CA -> intermediate CA -> client certificate。如何验证收到的证书是否是由“根 CA”显式创建的?

验证整个链条不是问题。这可以这样做:

X509Certificate2 rootCert = new X509Certificate2(rootCertFile);
X509Certificate2 intermediateCert = new X509Certificate2(intermediateCertFile);
X509Certificate2 clientCert = new X509Certificate2(clientCertFile);

chain.ChainPolicy.ExtraStore.Add(rootCert);
chain.ChainPolicy.ExtraStore.Add(intermediateCert);

if(chain.Build(clientCert))
{
    // ... chain is valid
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是证书根据(Windows)证书存储进行验证,但我只想根据特定的根 CA 对其进行验证。

我还认为可以检查是否chain.ChainElements包含我期望的根 CA。但是,如果有人从不同的根 CA 向我发送一条有效链并仅添加我期望的根 CA,该怎么办?

bar*_*njs 6

The certificate chain API checks that each element signed the preceding element, so there's no way that someone can just tack your root CA on the end (provided you're not using something like a 384-bit RSA key with MD5 signatures, in which case they can just forge your signature).

You can encode any extra checks that you like, such as that you know none of your chains will exceed length 3 (though you could just have encoded that in your root CA's X509 Basic Constraints extension).

if (!chain.Build(cert))
{
    return false;
}

if (chain.ChainElements.Length > 3)
{
    return false;
}

X509Certificate2 chainRoot = chain.ChainElements[chain.ChainElements.Length - 1].Certificate;

return chainRoot.Equals(root);
Run Code Online (Sandbox Code Playgroud)

If you prefer the last line could be return root.RawData.SequenceEquals(chainRoot.RawData); (ensure they have the same bytes).

Some things of note:

  • When you call X509Chain.Build() every X509Certificate2 object it returns via an X509ChainElement is a new object. You may wish to Dispose any of the objects you aren't returning (which may be all of them).
  • 即使 chain.Build 返回 false,它也会填充 ChainElements 数组,以便您可以检查原因。
  • X509Chain 对象本身是一次性的,您可能想要处置它(您可能已经在代码片段之外执行此操作)。
  • 处置链不会处置任何创建的证书,因为您可能已经持有对象引用。