Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate a certificate chain from a specific root CA in C#

I have a certificate chain that looks like this: root CA -> intermediate CA -> client certificate. How can I validate that a received certificate is explicitly created by "root CA"?

To validate the whole chain is not a problem. This can be done like this:

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
}

The issue here is that the certificate gets validated against the (Windows) certificate store but I just want to validate it against a specific root CA.

I also thought that it would be possible to check if the chain.ChainElements contains my expected root CA. But what if someone sends me a valid chain from a different root CA and just adds the my expected root CA?

like image 902
Tharnas Avatar asked Mar 06 '17 10:03

Tharnas


People also ask

How do I validate root CA?

The only you can verify is whether the certificate is valid for the usage at the requested level of certificate chain. If the certificate is the right one, it will be accepted, otherwise -- rejected.

How do I check a root certificate?

You can check if the correct root certificate is installed by querying our platform using the following cURL command: curl --verbose https://live.cardeasexml.com/ultradns.php . If the connection is successful and verified by the root certificate, you will see the following entry below.

How do I validate a CA?

To verify a certificate, a browser will obtain a sequence of certificates, each one having signed the next certificate in the sequence, connecting the signing CA's root to the server's certificate. This sequence of certificates is called a certification path.


1 Answers

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);

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).
  • Even when chain.Build returns false it will populate the ChainElements array so you can inspect why.
  • The X509Chain object itself is Disposable, you likely want to Dispose it (which you might already be doing outside of your snippet).
  • Disposing the chain won't Dispose any of the created certificates, since you could have been holding an object reference already.
like image 63
bartonjs Avatar answered Sep 20 '22 17:09

bartonjs