So a customer asked me last week if I could provide them some managed code to allow them to insert a certificate and a private key into the certificate store on a Windows CE device. A simple enough request, right? Heh, isn’t that how they all start?
To be honest, I’ve done very little work with certificates in the past – basically I’ve created certs for use with Padarn and SSL but that’s about it. So my first order of business was to do some due diligence to try to get an idea of the scope of the problem. I pulled up the MSDN docs of the Compact Framework’s support for X509 stuff. It shows that there is device support for the X509Store as well as the X509Certificate so I told them it should be pretty easy to achieve their goal. I mean the docs sure look like it would be easy.
Next I needed to write a little code to familiarize myself with the object model. I fired up a device that most definitely has several certificates installed.
Then I wrote some simple code to give me an idea which of the six stores these fall into:
public void DumpCertCounts()
{
Debug.WriteLine(” Current User Local Machine”);
var userStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
var deviceStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
Debug.WriteLine(string.Format(“Root: {0} {1}”,
userStore.Certificates.Count,
deviceStore.Certificates.Count));
userStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
deviceStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
Debug.WriteLine(string.Format(“My: {0} {1}”,
userStore.Certificates.Count,
deviceStore.Certificates.Count));
userStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser);
deviceStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine);
Debug.WriteLine(string.Format(“CA: {0} {1}”,
userStore.Certificates.Count,
deviceStore.Certificates.Count));
}
Easy enough. The problem was that then I actually ran the code. This is the output.
Really? Zero certificates in any store? Was my code right? Yes. Did I target the right device from the debugger? Yes. Alrighty, so it seems that “existence of a class in the BCL” doesn’t necessarily mean “actual functionality is implemented.” This doesn’t bode well.
Technically I don’t need to know what certificates are installed on the device for the customer’s request, right. Sure, it would be nice to see if a cert is there before trying to install it, but we can always just wrap the call in a try/catch and ignore any exception thrown when we try to install a duplicate. Not the ideal solution, but workable since this will be done infrequently.
I then generated some test certs with makecert.exe and pushed them to the device. Now I needed to create code to import them, hopefully an import works better than enumerating existing certs.
Let’s see, how would we bring in a cert? How about the Import method on the X509CerticateCollection? Oh, not supported in the CF.
Ah, but the Add method is, so I just need to create an X509Certificate and Add it. Let’s see, the X509Certifiacte class has two static methods – CreateFromCertFile and CreateFromSignedFile. Of course those aren’t supported in the CF. That would be too easy.
How about from a constructor? Looks like the only constructor supported is the one that takes in a byte array. What on earth is that byte array. Oh, the example shows that it’s easy to get by Exporting from a certificate you already have. How un-useful is that?
So it appears that the entire namespace in the Compact Framework is useless. Actually worse than useless because I can’t create a direct replacement or I’ll end up with naming conflicts with the existing useless garbage.
So now I have to create the objects in the namespace and implement the methods required to achieve “import a certificate into the device store”. The starting point is the C source code for the Certificates control panel applet you see above, which ships with Platform Builder. It’s an ugly load of P/Invoking methods that deal with lots of pointers to structs that contains pointers to structs that contain pointers to structs that contain…you get the idea.
So I spent a day just getting the import of a CER file working (much easier than the PVK import is going to be) and my exact same test code now outputs this:
See, an implementation that actually does something. I have no idea what was going on at Microsoft when this namespace was “implemented” or how it got out the door. It definitely wouldn’t pass even the most rudimentary of functional tests.
This is a classic case of why I’d love to see the Compact Framework open/shared sourced. I could actually go in and fix these things.
I think it would be great if Microsoft gave someone like you the code to the CF so that it could move forward. Of course, you’d probably turn into some evil tyrant, but at least you are capable of moving the project forward.
I’d like to think I wouldn’t be an evil tyrant if I had it. More like an ER doc trying to keep it breathing so it can continue to live and, just maybe, grow.
ctacke, you need to add .Open(OpenFlags.ReadOnly), then you will be able to read it.
Evandro, it’s way more that just opening it as read-only. The CF is missing a huge swath of functionality.