24

Facing a really strange issue X509Certificate2.Verify() returning false for a valid certificate. Maybe some has already faced this strange scenario before and can shine some light on it.

I am using openssl to generate client certificates for testing purposes. I create a Root CA and generate a client certificate based on that Root CA and add the Root CA to its chain.

I load the Root CA and the Client Cert to the local certificate store and it seems ok there but when I load it from my NUnit code to test X509Certificate2.Verify() always returns false.

enter image description here

Here is the code to load the Cert from the store:

        X509Store store = new X509Store(StoreName.My);
        string thumbprint = "60 d1 38 95 ee 3a 73 1e 7e 0d 70 68 0f 2d d0 69 1e 9a eb 72";
        store.Open(OpenFlags.ReadOnly);
        var mCert = store.Certificates.Find(
                                X509FindType.FindByThumbprint,
                                thumbprint,
                                true
                              ).OfType<System.Security.Cryptography.X509Certificates.X509Certificate>().FirstOrDefault();
        if(mCert != null)
        {
            var testClientCert = new X509Certificate2(mCert);
        }

Here is the Client Cert that I have just generated: (the CRL url is accessible from my local machine correctly)

-----BEGIN CERTIFICATE-----
MIIC7jCCAlegAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMR0wGwYDVQQKExRWaXRh
bEhlYWx0aCBTb2Z0d2FyZTElMCMGA1UECxMcVml0YWxIZWFsdGggU29mdHdhcmUg
Um9vdCBDQTElMCMGA1UEAxMcVml0YWxIZWFsdGggU29mdHdhcmUgUm9vdCBDQTAe
Fw0xNTAyMjcwODQ2MzNaFw0xNjAyMjcwODQ2MzNaMEUxHTAbBgNVBAoTFFZpdGFs
SGVhbHRoIFNvZnR3YXJlMREwDwYDVQQLEwhQbGF0Zm9ybTERMA8GA1UEAxMIVGVz
dFVzZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOkfyjX0PSnRYrBbCC8u
rw7IiFdAUj6frPKEmt0TLAR/4g+NazKdGjRRqxE9mNwX/2zGhIcucfGDVwPtOtiV
opicQEzGiSQkvAc+473MN5D6j3XtBYblALMeMyEYoh3LnHO4K+6kV6XE4BXV/2lV
mAVgXGkZzaayd40DLvg48vPlAgMBAAGjgcUwgcIwCQYDVR0TBAIwADARBglghkgB
hvhCAQEEBAMCB4AwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMDEG
CWCGSAGG+EIBDQQkFiJPcGVuU1NMIENlcnRpZmljYXRlIGZvciBTU0wgQ2xpZW50
ME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9wbGF0Zm9ybWRhc2hib2FyZC5ubC52
aXRhbGhlYWx0aC5sb2NhbC9wb3J0YWwvY3JsLmNybDANBgkqhkiG9w0BAQUFAAOB
gQBXYSmZaVu6vnyl94SO4qpNOutsUm4p7fQHehljhZ+aRrXE10rivWCt4g0k961E
PDsp4J0DR6uth6et42pBp8v2gFIGSQY/F7NhmOAsOJvM7z0oIBxMLcclIDTygbRp
KjZZpNjvf+YJasbidosiL4VSeRiCZ+HPzvKDb3wNeafoZA==
-----END CERTIFICATE-----

And here is the CRL file that gets download when I access it from the browser:

-----BEGIN X509 CRL-----
MIIBMjCBnDANBgkqhkiG9w0BAQUFADBtMR0wGwYDVQQKExRWaXRhbEhlYWx0aCBT
b2Z0d2FyZTElMCMGA1UECxMcVml0YWxIZWFsdGggU29mdHdhcmUgUm9vdCBDQTEl
MCMGA1UEAxMcVml0YWxIZWFsdGggU29mdHdhcmUgUm9vdCBDQRcNMTQwODA3MTQz
OTIyWhcNMTQwOTA2MTQzOTIyWjANBgkqhkiG9w0BAQUFAAOBgQA8MSxAorbxpdDm
1IA2Aqjb/OkZydua1Tm5k5KtHknI4zyYPZb3GzO0eRygpKBSAqtYkxDI6eCv6xgf
+anXT56md+cPGZ+2YvSicxqwP2GL2kymc9mVMTiQieioS1/7apjCIjZEgWxqf3Up
zvy/kNQRg3lII8hYu0idGs9byKZJFQ==
-----END X509 CRL-----
Crypt32
  • 12,850
  • 2
  • 41
  • 70
Deb
  • 737
  • 1
  • 5
  • 20
  • There's a few questions relating to this, like this one: http://stackoverflow.com/questions/1277791/x509certificate2-validation-on-web-service Have you tried any of these yet? – weston Feb 27 '15 at 09:25
  • @weston Yes, indeed. I checked the following link which seems to be like mine, http://stackoverflow.com/questions/10137208/x509certificate2-verify-method-always-return-false-for-the-valid-certificate?rq=1 but then I can access the CRL url in my client cert just fine from the browser and I am using Nunits tests which runs under the local Windows user account which I used to install the Cert and its RootCA to the current Cert store for this Windows user. – Deb Feb 27 '15 at 09:41
  • please, export this certificate to a file and show us certutil command output: `certutil -verify -urlfetch \file.cer`. – Crypt32 Feb 27 '15 at 10:28
  • @CryptoGuy thank you very much for the answer - that was really helpful. I did what you asked and here is the output: [link to the screenshot of the certutil command output](http://imgur.com/nQxjPp5) – Deb Mar 06 '15 at 10:20
  • Thanks, it is helpful, but not suffient. Please, update your post and include issuer certificate. – Crypt32 Mar 06 '15 at 11:46

1 Answers1

40

According to the X509Certificate2.Verify documentation

This method builds a simple chain for the certificate and applies the base policy to that chain. If you need more information about a failure, validate the certificate directly using the X509Chain object.

Therefore I would try to build chain using this code (replace Log method with your own implementation, I was using Console.Writeline)

X509Chain chain = new X509Chain();

try
{
    var chainBuilt = chain.Build(testClientCert );
    Log(string.Format("Chain building status: {0}", chainBuilt));

    if (chainBuilt == false)
        foreach (X509ChainStatus chainStatus in chain.ChainStatus)
            Log(string.Format("Chain error: {0} {1}", chainStatus.Status, chainStatus.StatusInformation));
}
catch (Exception ex)
{
    Log(ex.ToString());
}

This code will tell you the reason why the certificate could not be verified. If you need to adjust chain policy then set chain.ChainPolicy property i.e.

chain.ChainPolicy = new X509ChainPolicy()
{
    RevocationMode = X509RevocationMode.NoCheck,
    VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid,
    UrlRetrievalTimeout = new TimeSpan(0, 1, 0)
};
pepo
  • 8,644
  • 2
  • 27
  • 42
  • Yes, true. But I first want to just do a basic check if the certificate is valid and then go onto checking the whole chain. I dont want to waste time on checking the whole chain (which by the way can be very big in my case) before the basic verification passes on the certificate which I think quite a simple and valid use case. – Deb Mar 06 '15 at 10:16
  • 1
    This code helped me figure out why Verify() was returning false. The chainStatus.StatusInformation returned the following: "The revocation function was unable to check revocation for the certificate." In your case, the status may be different, but I do believe that the above code is useful for troubleshooting. – user3308241 Mar 17 '16 at 18:27
  • 4
    @Deb Verify builds the whole chain, but throws it away. You may as well build it yourself (provided that you Dispose it (4.6) or call Reset on it (other) when done). – bartonjs Jul 06 '16 at 14:18
  • But the `chain.Build` always return true in mono. – sakiM Feb 06 '18 at 01:43