X509Certificate2.Verify() method always return false for the valid certificate

c#, x509certificate2

Solution

The X509VerificationFlags values are suppressions, so specifying `X509VerificationFlags.AllFlags` actually prevents Build from returning false in most situations.

The `RevocationStatusUnknown` response seems particularly relevant. Whichever certificate it is reporting that for cannot be verified to be not revoked. The `Verify` method can be modeled as

public bool Verify()
{
    using (X509Chain chain = new X509Chain())
    {
        // The defaults, but expressing it here for clarity
        chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
        chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
        chain.ChainPolicy.VerificationTime = DateTime.Now;
        chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;

        return chain.Build(this);
    }
}

Which, since it is not asserting `X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown` or `X509VerificationFlags.IgnoreEndRevocationUnknown` while requesting an X509RevocationMode other than `None`, fails.

First, you should identify which certificate(s) in the chain is(/are) failing:

using (X509Chain chain = new X509Chain())
{
    // The defaults, but expressing it here for clarity
    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
    chain.ChainPolicy.VerificationTime = DateTime.Now;

    chain.Build(cert);

    for (int i = 0; i < chain.ChainElements.Count; i++)
    {
        X509ChainElement element = chain.ChainElements[i];

        if (element.ChainElementStatus.Length != 0)
        {
            Console.WriteLine($"Error at depth {i}: {element.Certificate.Subject}");

            foreach (var status in element.ChainElementStatus)
            {
                Console.WriteLine($"  {status.Status}: {status.StatusInformation}}}");
            }
        }
    }
}

If you look at any failing certificate in the Windows CertUI (double-click the .cer in Explorer or in the Certificates MMC Snap-In), look for a field named "CRL Distribution Points". These are the URLs that will be retrieved during runtime. Perhaps your system has a data egress restriction that doesn't allow those particular values to be queried for. You can always try issuing a web request from your web service to see if it can fetch the URLs without the context of being in the certificate subsystem.

Problem

I am using smart card for authentication. The SecurityTokenService (authentication service) is hosted on my machine only. The smart card has a valid certificate and it's root certificate is also installed in Local Computer store on my machine. When I use `X509Certificate2.Verify` method to validate the certificate in my service, it always return `false`. Can someone help me to understand why X509Certificate2.Verify() method always return false? Note: I used `X509Chain` and checked for all the flags (`X509VerificationFlags.AllFlags`). When I build the chanin, it returns `true` with `ChainStatus` as `RevocationStatusUnknown`. EDIT 1: I observed that `X509Certificate2.Verify()` method returns `true` if i write this code in windows form application. It returns `false` only in the service side code. Why so? Strange but true!

Original source