How to verify X509 cert without importing root cert?

RainerM picture RainerM · May 23, 2011 · Viewed 10.5k times · Source

My program contains 2 root certs I know and trust. I have to verify certs of trustcenters and "user" certs issued by the trustcenters which all originate from these 2 root certs.

I use X509Chain class to verify but that only works if the root cert is in the windows certificate store.

I'm looking for a way to verify the certs without importing theeses root certs - somehow tell the X509Chain class that I do trust this root certs and it should check just the certs in the chain and nothing else.

Actual code:

        X509Chain chain = new X509Chain();
        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
        chain.ChainPolicy.ExtraStore.Add(root); // i do trust this
        chain.ChainPolicy.ExtraStore.Add(trust);
        chain.Build(cert);

Edit: It's a .NET 2.0 Winforms application.

Answer

David Orbelian picture David Orbelian · Jun 12, 2018

I opened an Issue on dotnet/corefx and they replied as follows:

If AllowUnknownCertificateAuthority is the only flag set then chain.Build() will return true if

  • The chain correctly terminated in a self-signed certificate (via ExtraStore, or searched persisted stores)

  • None of the certificates are invalid per the requested revocation policy

  • All of the certificates are valid under the (optional) ApplicationPolicy or CertificatePolicy values

  • All of the certificates' NotBefore values are at-or-before VerificationTime and all of the certificates' NotAfter values are (at-or-)after VerificationTime.

If that flag is not specified then an additional constraint is added:

The self-signed certificate must be registered as trusted on the system (e.g. in the LM\Root store).

So, Build() returns true, you know that a time-valid non-revoked chain is present. The thing to do at that point is read chain.ChainElements[chain.ChainElements.Count - 1].Certificate and determine if it is a certificate that you trust. I recommend comparing chainRoot.RawData to a byte[] representing a certificate that you trust as a root in context (that is, byte-for-byte compare rather than using a thumbprint value).

(If other flags are set then other constraints are also relaxed)

So you should do it this way:

X509Chain chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.ExtraStore.Add(root);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
var isValid = chain.Build(cert);

var chainRoot = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
isValid = isValid && chainRoot.RawData.SequenceEqual(root.RawData);