Wednesday, May 30, 2007

I've updated HttpConfig to fix a couple of 64-bit bugs.

Download: exe source

Wednesday, May 30, 2007 6:00:00 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Tuesday, December 05, 2006

At long last, I've been able to update the HttpConfig GUI tool. I've fixed many bugs, streamlined the UI, added graphical security editing and gotten the thing to run on Vista.

Thanks to Keith and Dominick for the inspiration to enhance the security stuff. Now that I'm using .NET 2.0 for this app, I was able to get the EditSecurity API working purely in C#.


Download: exe source

Tuesday, December 05, 2006 6:00:00 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Sunday, November 20, 2005

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.


Sunday, November 20, 2005 6:00:00 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Monday, November 07, 2005

One of the joys I�ve experienced in my recent dealings with the HTTP API and some lower-level SChannel code is that of trying to generate proper SSL test certificates. During the initial development phase of the product I�m currently working on, we used one common test certificate for all our test/dev servers. Later on, we began to generate different certificates for each server so that we could test some cert verification code and also verify that we knew exactly what was required of certificates to work with our product. Needless to say (or I wouldn�t have anything to write here), we immediately began to have many problems. Some servers worked just fine, while others failed. On the failing servers, test requests with WebRequest yielded the familiar but unhelpful error "Could not establish secure channel for SSL/TLS". Attempts to connect from IE produced the error "Cannot find server or DNS Error". In order to further troubleshoot, I tried making a connection using a plain SChannel-based SSL socket. The connection was established just fine and the client socket sent the hello message. As soon as the client socket attempted to read the server response, an exception was thrown, indicating that the connection had been closed by the server. Next, I enabled full SChannel logging on the server and restarted. Attempts to connect left 2 messages in the event logs: "Creating an SSL server credential", followed by "The SSL server credential�s private key has the following properties..." and NO error. Baffled, I installed Microsoft�s SSL Diagnostics utility and attempted a handshake simulation. This yielded the error "Unexpected error receiving data (0x80090304)", which error code is defined as SEC_E_INTERNAL_ERROR; again, a most unhelpful description. This led me on a week-long study of X.509 certificates, makecert.exe and the MS Crypto Providers� key container implementation. I�m going to omit many details here in order to get to the point, which is to enumerate the problems and solutions I�ve found for our situation. I�ll follow up with another post to describe the gory details of this research in some depth. Anyway, simply stated, the problem is that the certificate's private key is either inaccessible or the keyspec is incorrect.


Our problems basically boiled down to three root causes:

1 - Improper import of good certificates, which caused them to appear faulty.

2 - Use of a build of makecert.exe that generates key containers improperly

3 - Failure to realize that makecert.exe does not, by default, generate certs that use the correct keyspec for an SSL cert.

Problem #1 - The problem with importing was that I sometimes imported the certificate into the CurrentUser MY store and then, realizing that I'd imported into the wrong store, copied the cert into the LocalMachine MY store. The problem is that once a certificate is imported into a CurrentUser store, the private key container resides in the user�s profile, where it cannot be found by a system process.

Problem #2 - One of the first things I do when I create a development VM is to add the path to the .NET SDK bin directory to my system path. I always want access to the tools therein from any command prompt. Unfortunately, the makecert.exe in that directory (v5.131.2157.1) won�t work for generating SSL certs. The problem is that even if you specify a LocalMachine store for the cert, the private key container it generates is generated as a user key, not a machine key. Therefore, though everything looks good, when you use the cert from a system process, you experience the symptoms enumerated above. In order to use this build for SSL certs, you�d have to pre-generate the key container and reference the pre-created container on the makecert command line.

Problem #3 - There are two standard key types for RSA keys: signature and exchange. Which key is used is defined by the keyspec property of the private key context belonging to the certificate. The keyspec property must be set to "Exchange" in order for the cert to work for SSL. This is obvious to me, but I never realized that makecert.exe sets the keyspec to Signature by default, and there isn�t a standard interface to view this property of a certificate that I�m aware of.


Solution #1 - Import certificates intended for SSL usage into a LocalMachine store directly. Don�t try to copy a cert from a CurrentUser store into a LocalMachine store. If you�ve mistakenly imported a cert into a CurrentUser store, you need to delete the cert and the key container (deleting a certificate does not delete the key container), and then import the cert into a LocalMachine store. See my next post for details as to how to locate the key container and delete it.

Solution #2 - Don�t use v5.131.2157.1 of makecert.exe (the one in the .NET v1.1 SDK) to generate SSL certificates. It always generates user key containers, which won�t work from a system process. Fortunately, the version of makecert.exe (v5.131.3790.0) that ships with v2.0 of the .NET SDK, as well as the latest Platform SDKs, works properly.

Solution #3 - Always use the command line option "-sky exchange" with makecert.exe if you�re generating SSL certificates. If you don�t specify this, it will default to the signature keyspec, which won�t work for SSL.

The difficulties I�ve experienced have been compounded by the fact that any one or more of these problems could be combined in a single situation, making it terribly difficult to pinpoint precisely what is going on. To aid in the diagnosis of SSL certificate problems, I�m making available a little command line utility that I wrote for this purpose.

checkcert: exe source

To use checkcert.exe, pass a store name and a cert subject search string (such as the common name). Checkcert will display some key information about the cert that is not available in the built-in tools (again, that I�m aware of). Most importantly, checkcert will display the private key container location and the keyspec. You want to ensure that the key container location is "Machine" and that the keyspec is "Exchange" for an SSL cert. I hope this information and the utility will save someone the hassle of trying to unravel this mess from scratch.

Monday, November 07, 2005 6:00:00 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [7]  |  Trackback
 Friday, October 28, 2005

I've been doing a fair bit of development against the MS HTTP API lately, and I'm weary of the httpcfg.exe utility. First of all, it's a right pain in the neck to find in the first place. Once located and downloaded, it's equally painful to use, IMO. Having read several articles on the net about the woes others were also experiencing in using this tool, I decided to write a simple GUI application against the Http configuration APIs. It's called, quite simply, HttpConfig. It won't win any points for UI flash, but I do hope it will make life easier for some as it already has for me. Enjoy!

Download: exe source

Friday, October 28, 2005 6:00:00 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [26]  |  Trackback