C# X509Certificate2.Verify without revocation test

3k views Asked by At

I try to use X509Certificate2.Verify() function to check if a certificate chain is valid. The Verify function returns false and the ChainElementStatus returns "RevocationStatusUnknown".

Is there a way to use the Verify function without the check of the RevocationStatus? The RevocationStatus can't be checked without internet connection? Is there a other function to check the chain and certificates wihtout the RevocationStatus?

A dirty solution, is to check if the RevocationStatus is the only element in element.ChainElementStatus.

I already use X509RevocationMode.Offline and IgnoreCertificateAuthorityRevocationUnknown.

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

X509Chain ch = new X509Chain();

ch.Build(certificate);

ch.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
ch.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown;

Console.WriteLine("Chain Information");
Console.WriteLine("Chain revocation flag: {0}", ch.ChainPolicy.RevocationFlag);

Console.WriteLine("Chain revocation mode: {0}", ch.ChainPolicy.RevocationMode);
Console.WriteLine("Chain verification flag: {0}", ch.ChainPolicy.VerificationFlags);
Console.WriteLine("Chain verification time: {0}", ch.ChainPolicy.VerificationTime);
Console.WriteLine("Chain status length: {0}", ch.ChainStatus.Length);
Console.WriteLine("Chain application policy count: {0}", ch.ChainPolicy.ApplicationPolicy.Count);
Console.WriteLine("Chain certificate policy count: {0} {1}", ch.ChainPolicy.CertificatePolicy.Count, Environment.NewLine);

//Output chain element information.
Console.WriteLine("Chain Element Information");
Console.WriteLine("Number of chain elements: {0}", ch.ChainElements.Count);
Console.WriteLine("Chain elements synchronized? {0} {1}", ch.ChainElements.IsSynchronized, Environment.NewLine);

foreach (X509ChainElement element in ch.ChainElements)
{
Console.WriteLine("Element issuer name: {0}", element.Certificate.Issuer);
Console.WriteLine("Element certificate valid until: {0}", element.Certificate.NotAfter);
Console.WriteLine("Element certificate is valid: {0}", element.Certificate.Verify());
Console.WriteLine("Element error status length: {0}", element.ChainElementStatus.Length);
Console.WriteLine("Element information: {0}", element.Information);
Console.WriteLine("Number of element extensions: {0}{1}", element.Certificate.Extensions.Count, Environment.NewLine);

    if (ch.ChainStatus.Length >= 1)
    {
        for (int index = 0; index < element.ChainElementStatus.Length; index++)
        {
            Console.WriteLine(element.ChainElementStatus[index].Status);
            Console.WriteLine(element.ChainElementStatus[index].StatusInformation);
        }
    }
}

Result:

Chain Information Chain revocation flag: ExcludeRoot Chain revocation mode: Offline Chain verification flag: IgnoreCertificateAuthorityRevocationUnknown Chain verification time: 19.11.2018 07:53:31 Chain status length: 1 Chain application policy count: 0 Chain certificate policy count: 0

Chain Element Information Number of chain elements: 2 Chain elements synchronized? False

Element issuer name: CN=TestRootCA Element certificate valid until: 01.01.2019 00:00:00 Element certificate is valid: False Element error status length: 1 Element information: Number of element extensions: 5

RevocationStatusUnknown Die Sperrfunktion konnte keine Sperrprüfung für das Zertifikat durchführen.

Element issuer name: CN=TestRootCA Element certificate valid until: 01.01.2019 00:00:00 Element certificate is valid: True Element error status length: 0 Element information: Number of element extensions: 2

1

There are 1 answers

2
bartonjs On BEST ANSWER

I already use X509RevocationMode.Offline and IgnoreCertificateAuthorityRevocationUnknown.

What IgnoreCertificateAuthorityRevocationUnknown means is "don't make chain.Build return false for this reason."

Of course, you set it after calling chain.Build, and you didn't check the return value from chain.Build.

If you want to ignore revocation, set ChainPolicy.RevocationMode to X509RevocationMode.NoCheck. If you want it to be checked if it's already cached, and ignored if it's not, then setting the mode to Offline and asserting all of the RevocationUnknown flags does that.

The Boolean return from chain.Build is true if the certificate/chain passed all validity checks that were not marked as ignored via the VerificationFlags value.

So the shortest "tell me if this certificate is not expired, has a resolvable chain, the terminus of the chain is something I trust, and I don't care about revocation" is

using (X509Chain ch = new X509Chain())
{
    ch.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

    return ch.Build(certificate);
}

Opportunistic revocation would be

using (X509Chain ch = new X509Chain())
{
    ch.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
    ch.ChainPolicy.VerificationFlags =
        X509VerificationFlags.IgnoreEndRevocationUnknown |
        X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown |
        X509VerificationFlags.IgnoreRootRevocationUnknown;

    return ch.Build(certificate);
}