As indicated in my last post, I'm posting a wrap-up to the SSL cert saga. Unfortunately, I've waited too long between posts and forgotten some of what I had intended to write here. However, since I included more details in the last post than I had intended, you're not missing much.
One of the more interesting tasks involved in researching SSL cert problems was how to locate the key containers. The manner in which key containers are persisted is not documented anywhere that I know of, and I'm sure that's intentional as key container persistence is an internal implementation detail. I knew from some work several years ago that the MS RSA providers persist the key containers in the file system. I also remembered the approximate location, but I couldn't remember all the details. I fired up filemon and my memory was refreshed. The keys are stored in the common or user profile, depending on whether the container is a machine or user keyset. However, the containers are named in some bizarre guidish/hashy-looking format, so it's not obvious at a glance which files belong to which key containers. I was able to locate older key containers by opening them in TextPad because the name of the container is embedded in ASCII text within the file itself. New containers were easy to locate simply by sorting the files. However, I wanted to know how the filenames are derived. I have a sick mind that way. I always want to know how things work behind the scenes. After a few hours with FileMon, RegMon and the disassembler, I finally think I understand how these filenames are derived. I'm going to document this process here for the curious and so I can find this information the next time I need it. This information is applicable to Win2K, WinXP and Win2K3. I don't yet have a Vista box to test this on, so I don't know if it remains the same in that version of the OS.
First of all, the key containers are persisted in the following locations:
User keys: %PROFILE%\Application Data\Microsoft\Crypto\RSA\[SID string]
Machine keys: %ALLUSERS%\Application Data\Microsoft\Crypto\RSA\MachineKeys
The filenames look like so: d99e964c16600b1681cdfbad2d5d5eac_2f896382-3658-492e-9219-ce847feb6b8a
The filename consists of a MD5-derived prefix and the MachineGuid, separated by an underscore. The MachineGuid is a registry string value, located under the key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography". The hash prefix is derived by performing the following operations:
1 - Obtain the name of the key container. The private key container name for a cert can be obtained via the CertGetCertificateContextProperty API, specifying the CERT_KEY_PROV_INFO_PROP_ID property. You can also obtain the key container name by using the checkcert utility from my last post.
2 - Convert the key container name to lower case.
3 - Append a null character
4 - Convert the string to ASCII bytes
5 - Perform an MD5 hash of the ASCII bytes
6 - Treat each 4 byte block of the hash as a 32-bit integer, reversing each
7 - Convert the resulting bytes to a hex string
I'm including a sample class that demonstrates the code necessary to calculate the full path and filename of an RSA key container. The class exposes a static method called "GetRsaKeyContainerFilename" as well as methods that will allow you to perform each step of this operation separately.
There may be an API to do this, but I haven't been able to find it. I wasn't as concerned with an easy way to do this as much as understanding the process, anyway.