I bet, from the commonality of the task I was facing, that there must be tons of others in my shoes. But amazingly, I did not find many good articles out there discussing a solution. Let me put it this way - there are a lot of articles discussing what I needed, but most of them discuss the problem, not the solution. So, armed with bits and pieces of information from everywhere, and my own 2 cents, I managed to find out how exactly to do the following: set up the IIS on your own machine to do HTTPS, and then create a client certificate for mere testing purposes if your client program needs to send one with its request. All this not using Win 2003 or Certificate Authority or Certificate Server. I was using XP Professional and IIS 5.0 - but this should work with IIS 6.0 as well.
This is a technique article, it involves steps, some of which I cannot explain like an expert. I do not know Perl, and I am definitely not an IIS Administrator. All I am is part of a team that wrote a C# client program which must access a 3rd party web service. This web service is protected like a fortress - it is an HTTPS link, and it requires its clients to use a client certificate. It also has HTTP Basic Authentication mechanism. Having written the client program and tested it functionally, my team had to test it "environmentally". Rather than involving the 3rd party developers to let us in for testing, we quickly wrote a dummy web service (again in C#) that follows the same WSDL as theirs. Having done that, our next goals were to:
- Host this dummy web service so that it can be accessed using a HTTPS URL
- Make our client program send a client certificate to the dummy web service
- Make this dummy web service "HTTP Basic Auth - protected"
- Make our client program send the HTTP Basic Auth credentials to the dummy web service
In this article, I will describe how the 1st two bullets above can be achieved. The remaining two are actually easy - you will find lots of articles on how to do that. If you still cannot find, just drop me a comment, I will share.
Working with Server Certificates
First of all, a brief explanation of what a "server certificate" is. When you install IIS and host a web service, you are the server. Anybody who calls that web service (like a client program or Internet Explorer browser window) is the client. If you install a server certificate on your server (IIS), clients can call your web service with a HTTPS in the URL. If they do, and if the client is the browser, it may receive a warning dialog box. But if the client is a program, you could write the code in such a way that the warning dialog box is programmatically responded with a "YES". In this article, I will assume that you know to write all that code - this article is only about setting up - things you do after writing and compiling the code, so that you could test it. However, if you still want to know the exact coding technique, please feel free to drop me a comment.
What does a server certificate achieve? Simple: It allows or enables clients to call with "HTTPS" in the URL. What that does is that it kicks in the HTTPS protocol instead of HTTP, and therefore, encrypts the data before sending it to the server. And vice versa. Remember that depending on how you (I mean the server owner) configure your IIS, the client can either:
- be forced to always use HTTPS, or
- have the option of either using HTTP or HTTPS
We will see that soon at a later point.
Tools You Will Need
- OpenSSL binaries zip file: Go to http://sourceforge.net/project/showfiles.php?group_id=23617&release_id=188569, search (CTRL+F) with "openssl", click the first occurrence, in the resulting page, download the "...bin.zip" file. Alternatively, here is the direct download link: http://downloads.sourceforge.net/gnuwin32/openssl-0.9.7c-bin.zip?modtime=1065139200&big_mirror=1.
- OpenSSL source zip file: follow the same steps as the point above, but download the "...src.zip" file. Alternatively, here is the direct download link:http://downloads.sourceforge.net/gnuwin32/openssl-0.9.7c-src.zip?modtime=1065139200&big_mirror=1
- Some software that can run a PERL script. I used ActivePerl. To get ActivePerl (it is a freeware), go to activeperl homepage (http://www.activestate.com/Products/ActivePerl/) and follow the download links, choose your platform, etc. I had downloaded the MSI file and installed ActivePerl.
Why do you need to run a Perl script? Because IIS does not allow you to create a server certificate directly. But it does allow you to create a "request for a certificate". In the real world, you would typically create such a request, and then submit it to external companies to issue you a certificate based on that request. But what we are going to do is we will use OPENSSL's open source freeware to create a server certificate from that request (instead of contacting an external company). This open source is a Perl script (as you will soon see). So you need something that runs PERL. That's why.
- Unzip both the ZIP files from 1 and 2 above. The bin zip will create a bin folder - it will have OPENSSL.EXE and 2 DLLs. Copy all these 3 files to the "...\src\openssl-0.9.7c\apps" subfolder created from the other zip file (src.zip).
- In the apps subfolder, there will be a file CA.PL. This is a Perl script. Open it in some text editor. There will be a line:
Change it to:
Save and close the file.
- Open up Internet Information Services (IIS) control panel window. Go to "Default web site", right click, Properties, Directory Security tab, click on the "Server Certificate..." button inside the "Secure Communications" group box. Click Next on Wizard. Select radio "Create a new certificate" and next. Select "Prepare the request now, but send it later", next. In the next few screens, enter anything you like, or accept the defaults - those are the names, etc. Finally, the wizard will ask you the name and location of the request file. It will suggest CertReq.TXT. I had accepted that name. You have to provide the full path, like "C:\CertReq.TXT". Finish. Your request file is ready.
- Copy the CERTREQ.TXT from step 3 above to the "apps" subfolder (referred to in step 2). Rename it to "newreq.pem".
- Open a command window. "cd" to the apps folder. Run the 2 commands (in that order):
perl CA.pl -newca
perl CA.pl -signreq
- The above step will create a file "NewCert.PEM" inside apps. Open this in any text editor. Remove everything before the line "-----BEGIN CERTIFICATE-----". (Make the line -----BEGIN CERTIFICATE----- your 1st line). Save. Close.
- Go back to IIS and click the same button "Server Certificates..." as you clicked in step 3 above. Now the radios will be different. Select the "Process the pending request and install the certificate" radio and Next. Browse to the newcert.pem file in the apps folder (you will need to set the file selection filter to All Files to be able to see it). Click Next to finish. You now have a server certificate installed on your IIS. Which means right now, clients can call you using either HTTP or HTTPS.
- Again, from the IIS window, go to "Default web site", right click, Properties, "Web Site" tab, click the Advanced button, in the group box "Multiple SSL identities for this website", ensure that the IP Address is "Default" for port 443.
- At this stage, any web service you are hosting can be accessed using HTTPS. Try accessing your web service from the browser using HTTPS - you should get the warning window. But, even now, the option of using HTTP or HTTPS exists. If you want to configure any specific web service to be only accessible to HTTPS requests, here is how to do that:
- In the IIS wiindow, right click on the virtual directory of the web service you want to configure. click Properties. Directory Security tab. Edit... button. Check the box "Require Secure Channel (SSL)" Apply, OK out. From this point, you cannot call that particular web service using HTTP. It has to be always called using HTTPS URL.
- If you apply this change not to a specific web service or web application, but to the entire IIS instance (right clicking on "Default web site" instead of a specific virtual directory) - then all the web services or applications you host will need HTTPS access, none of them will respond to a HTTP request.
Working with Client Certificates
You cannot easily create a client certificate without software like Microsoft Certificate Server. But having said that, I did find a workaround for my specific need. So may be this work around may help you! That is why I am listing it here.
The first step is to configure your web service to require a client certificate. In the IIS window, right click on the virtual directory corresponding to your specific web service, click Properties. Directory Security tab. Edit... button. Select the "Require Client Certificates" radio, OK out. Now your web service is configured to require a client certificate. Which means any client calling it MUST send a client certificate with the request.
Go ahead and try to call your web service using the browser, see what happens.
But where would I get a client certificate from? The client program that we needed to test accepted a CER file path through configuration entries and added a X509 certificate object created from that CER file to the request's Certificates collection. In production, this 3rd party would provide us with a correct CER file. The deployment team will simply keep the CER file wherever I tell them to, and update the CONFIG file with its path. But how will I know that the code will work? I need to test it right now, right here!
Of course, I could tell that the code was working if we left the CER File config entry blank. Which means it would not find any CER file to bundle with the request, and hence send the request without any CER file. In that case, and having configured the dummy web service to require a client certificate, we received SOAP errors (protocol error to be exact). That was expected.
Then this idea struck me. I myself browse the internet like an addict. Surely there would be some client certificates installed on my machine (that the browser uses to send to some web site that needs them). Why not try to export a CER file from any one of them? With Internet Explorer, here is how you do that: Open Internet Explorer, Tools --> Internet Options, Content tab, Certificates button, and the resulting dialog has many tabs. Starting from the tab "Personal" in the very left to the tab "Untrusted Publishers" to the very right - there is a delightfully large number of client certificates installed on my machine. I selected any one of them. As soon as you select a certficate, the Export... button becomes enabled. Click it, click Next, select "DER Encoded Binary X.509 (.CER)", click Next, give a full path and name (that ends in .CER), and export the certficate. Well, here was my CER file.
But the fact remained that I was using just any random CER file. I was not using the one and only one that my web service needed. But I will leave complementing my explanation to my audience (to make it complete) - why it worked. I am keen to know the reason, too. So please leave a comment if you have a more correct explanation than me of the following fact: I used that CER file in my client program, and it worked fine! It called my dummy web service without any hiccups. The protocol error was no more coming, and that proves that the client code is capable of bundling a client certificate and sending it to its target web service just fine!
My explanation (might not be adequate) goes like this:
I have not configured my web service to do anything meaningful (like validation) with the client certificate. If I had done so, using just any random client certificate would not have worked. But as far as my testing was concerned, I had just proved that the code works, and that was my goal. After all, in real life, my client code will call a 3rd party web service, that would provide their own CER file. So I did not need to know what they would do with that CER file once my client program bundled and sent it along with the SOAP request!
Of course if you are reading this article as the web service author, and want to use a client certificate being sent to you by a caller, then my small experiment does not help you directly. Anyway, if you find that out, and want to share, so that the cyberspace is a little more enriched, please leave a message for everybody.
This was largely an article on how I had reacted to a particular problem. And it seemed to be a problem that many others would very likely face. That prompted me to write this up. Please pardon lack of in depth explanation in certain areas.
Also, this article refers to small bits and pieces of code which I have not elaborated. Please let me know if you need to get a hold of them.
- 9th March, 2007: Initial post