4

I am using the following code to get only the valid (by time) certificates on the machine:

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var storeCol = store.Certificates;
store.Close();

var notExpiredCol = storeCol.Find(X509FindType.FindByTimeValid, DateTime.Now, true);

On my machine it's working perfectly. But, on another machine with same configuration (Windows 10, Visual Studio Community 2017 and exactly the same certificate installed), it returns nothing.

The original collection from the store, without filters, has the certificate. If we look at the certificates under Internet Explorer, the certificate is there. If we look under MMC with Certificates snap-in, the certificate is there. We tried installing the certificate under Current User and Local Machine, the code is getting the certificates collection from Current User.

I've just tried using FindByTimeExpired and FindByTimeNotYetValid criteria, and same result, both returns an empty collection:

var expiredCol = storeCol.Find(X509FindType.FindByTimeExpired, DateTime.Now, true);
var notYetValidCol = storeCol.Find(X509FindType.FindByTimeNotYetValid, DateTime.Now, true);

Does anyone have any idea what's going on or what we could check to resolve the issue?

By the way, what is exactly the role of the validOnly parameter on the X509Certificate2Collection.Find() method? If I use the value false on it, the method returns the certificate on the collection.

Pedro Gaspar
  • 777
  • 8
  • 35
  • 7
    `validOnly` will cause the `X509Store.Find` function to call [`Verify`](https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.verify(v=vs.110).aspx) on any certificates that it finds. In your case, it's likely that the certificate is not trusted on the other machine. – Kirk Larkin Aug 10 '17 at 20:13
  • That was exactly the case, you've nailed it Kirk, thanks! Microsoft documentation on X509Certificate2Collection.Find() method should mention that _little particularity_ of the `validOnly` parameter though. – Pedro Gaspar Aug 10 '17 at 20:38
  • 1
    I went into the Mono source code for that function and found its usage there: https://github.com/mono/mono/blob/master/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs#L304. – Kirk Larkin Aug 10 '17 at 20:43
  • Wow, that was a lot of work to find the answer! Docs could had made our lifes easier, isn't it? By the way, you know that Microsoft gives the source code for Windows implementation also? [Here](https://github.com/Microsoft/referencesource/blob/4fe4349175f4c5091d972a7e56ea12012f1e7170/System/security/system/security/cryptography/x509/x509certificate2collection.cs) and [here](https://referencesource.microsoft.com/#System/security/system/security/cryptography/x509/x509certificate2collection.cs,5915aa512d90d171,references). – Pedro Gaspar Aug 10 '17 at 21:15
  • But there (on source code for the Windows implementation of the .NET framework) it was a little more complicated to find out the answer. `X509Certificate2Collection.Find()` method calls `FindCertInStore()` function, that calls `FindByCert()` function, that finally calls `X509Utils.VerifyCertificate()`. But [X509Utils](http://referencesource.microsoft.com/#System.Security/system/security/cryptography/x509/x509utils.cs,102ed174fabebd08,references) is an internal class... On Mono source code it was a lot easier to understand what was going on. Thanks again, Kirk. – Pedro Gaspar Aug 10 '17 at 21:17
  • But, in the end, `X509Certificate2.Verify()` does call `X509Utils.VerifyCertificate()` much like the `X509Certificate2Collection.Find()` method with `validOnly` argument does: https://referencesource.microsoft.com/#System/security/system/security/cryptography/x509/x509certificate2.cs,9de443eec7b07214 – Pedro Gaspar Aug 10 '17 at 21:48

1 Answers1

10

@Kirk Larkin solved the problem on his comment.

The validOnly parameter set to true causes X509Certificate2Collection.Find() method to call X509Certificate2.Verify() method on any certificate it finds (just don't know why the docs don't mention that little particularity though), and that method performs a X.509 chain validation.

On that machine, one Trusted Root Certification Authority in the certificate chain was not installed, so, the certificate was being treated as not trusted. We've installed that missing certificate of the chain and now it works well.

So, better not use the validOnly parameter set to true on our case.

Pedro Gaspar
  • 777
  • 8
  • 35
  • More information on `validOnly`: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/e619fec3-a209-4981-a499-30f4b5d34135/x509certificate2collectionfind-what-is-a-valid-certificate?forum=clr – Ohad Schneider Apr 25 '20 at 17:24