简体   繁体   中英

How to correctly use X509Store?

I've been using X509Store and his friends, X509Certificate2 and X509Certificate2Collection . Everything was fine, but I've started to write tests for my code, and I've run into a problem. I generate a new test cert and install it to start each test, then remove the test cert at the end. The test certificates are non-deterministically not valid, despite having creation dates a day in the past and expiry dates a day in the future.

I've noticed that running a full GC and waiting for finalizers in TearDown fixes the tests.

I've been digging into the reference source here. It seems that X509Certificate2 needs to be disposed, otherwise operations that already returned success (like adding to a store) can have not been flushed to the actual store (this is a behaviour of the Windows API, see CertCloseStore CRYPT_E_PENDING_CLOSE result).

It further seems that X509Certificate2Collection is basically just a List<X509Certificate2> , so every time such a list of certs is created, every single instance needs to be disposed, such as reading the Certificates property on the store.

Furthermore, when the Find method is used, this involves creating a temporary store, adding the certs, and then reading the certs back out again from unmanaged code, creating a new collection of certs which also all need to be disposed.

Is this really the correct way to use the X509Store ? It seems to be unbelievable that the .NET API would be so tremendously unsafe and difficult to use correctly with silent failures and completely undocumented failure modes everywhere. Am I just missing something obvious or should these classes all be avoided?

What undocumented failure modes? You're supposed to dispose every single disposable object you own. This applies especially when you know you're dealing with native code. This is nothing specific to the certificate interfaces - files work the same way, database transactions work the same way, sockets work the same way. That's why the IDisposable interface exists in the first place - it's the common interface saying "call me when you're done". Did you stop using file I/O when you realized you're required to close the file? Or haven't you noticed that it's required yet?

The whole cryptography module that deals with SChannel is little more than a thin wrapper on top of SChannel. That is, almost every single thing you do is native interop, managed wrappers over native objects etc.

But it doesn't matter what the exact problem is. The key point is still that you're supposed to dispose disposables, always. Just because things seem to kind of work even if you don't doesn't mean it's fine to omit disposing objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM