Code Signing – It’s Cheaper and Easier than You Thought
One of the things I've always wanted to do, but never got around to, is to figuring out how to sign my code. Like most developers, I never really worried about code signing until Vista came along. Maybe it's just because I'm completely anal retentive, but I always felt a little guilty when my applications or installations that need administrator privileges show the dreaded UAC Cancel/Allow dialog:
To me, that just looks a bit unprofessional. I don't want to be known as "Unidentified Publisher." The main reason small shops or independent developers don't sign their applications is because the cost of a code signing certificate, sometimes called an ID, has always been very expensive. Checking VeriSign right now, they want $499 USD for a one year certificate and $1,293 USD for a three year certificate. For that much money you can get pretty nice laptop. Thus began my quest to see if I could get a code signing certificate for a reasonable price.
In this blog entry I'll show where I got a reasonably priced certificate and how to get your binaries and installs signed correctly. As I was reading how to make everything worked, there was no one place that showed all the parts from buying a certificate, to getting it on your machine, to getting you code signed in the real world. Hopefully this will help you out if you want to or are required to code sign.
Searching for code signing certificates turns up numerous companies that will sell you a certificate with prices ranging from $179 USD to $499 USD per year. They all offer cheaper options if you buy three year certificates, but they still cost more than a single developer probably wants to pay. Fortunately, the day I thought about getting a code signing certificate, Omar Shahine mentioned that TUCOWS, (I'm so old I remember the original "The Ultimate Collection of Winsock Software" web site!), is reselling Comodo digital certificates at $80 USD per year at their author specific web site. Even better is the three year price of $195 USD. That was price I could justify spending with the Robbins household CFO, AKA my wife.
After you purchase the certificate, you have to prove who you are. That's the whole reason it's called a "trusted certificate" in the first place. If you want the certificate in your name alone, you'll need to fax them a copy of your driver's license that shows the address you specified in the sign up pages. If you want a company name on the certificate you'll need to fax Comodo copies of your company's articles of organization and a business tax license. As I wanted my certificate to say "John Robbins/Wintellect" I faxed three documents and Comodo happily issued a certificate.
I had some trouble with registration process at Comodo. Make sure you add https://secure.comodo.net to the list of trusted sites in Internet Explorer so they can properly get you registered and install their trusted root certificate on your computer. You'll have to use the machine you registered with Comodo to retrieve you certificate. One thing that Comodo does not make clear is that they expect you to register at http://support.comodo.com to ensure you really sent in the request and interact with them if you need to ask questions. Finally, make sure to set any spam filters you are using to allow mail from comodo.com through so when you get your certificate issued, you'll actually get the mail. [Edit: 1/17, I want to make clear that the certificate from Comodo is trusted on all computers. You only need to install Comodo's certificate on the machine you are using to buy your certificate.]
When you get the email giving you the download address, you'll click on the link and download your certificate into the certificate cache on the machine. Since you'll want the certificate in file form to make signing easier, you need to get it out of the certificate store. On a Vista computer, the first step is to start the Certificate Manager snap-in, by running "certmgr.msc." The certificate downloaded from Comodo is in the Personal\Certificates section and the issuer is UTN-UserFirst-Object.
Right click on the certificate and select All Tasks, Export… That will bring up the Certificate Export Wizard. The first decision you'll have to make is if you want to export the private key information with the certificate. In nearly all cases, you'll need to choose "Yes, export the private key." The second decision is what data you want included in the Personal Information Exchange (.PFX) file you're exporting. What I chose to do was the following:
This allows you to have a complete certificate in the .PFX file. I chose to leave the private key in the Certificate Manager so I could export the key in multiple ways, which I'll discuss why in a bit. After clicking the Next button, you'll have to provide a password for the certificate. As I'm using Vista, that's required. A few things I read on the web said that with XP you could export a .PFX file with no password, which seemed quite dangerous to me. It goes without saying that you'll want to be careful with the password and actual .PFX file.
Once you've got the .PFX file on disk, it's time to sign something and that's where SIGNTOOL.EXE comes into play. Visual Studio 2008 Team Editions includes the latest Platform SDK so all you need to do is start a Visual Studio 2008 Command Prompt to get the path environment variable initialized. All that does is run the <Visual Studio Installation Directory>\VC\vcvarsall.bat batch file. If you do not have a Team Edition of Visual Studio, you can download the Vista Platform SDK here.
In the command prompt, type the following command to sign all the files you want to sign: (all one line)
signtool sign /f YourFile.pfx /p <password>
/t http://timestamp.comodoca.com/authenticode <files>
If you're signing a .MSI file, also add the /d command line option to specify the description of your install program so the user will see that instead of the temporary name Windows Installer actually uses for the installation. Once you've signed your binary, you'll look as professional as you the big guys:
If you are curious what DbgChooser is, see my January 2000 Bugslayer column in Microsoft System's Journal.
There are obviously more command line options to SIGNTOOL.EXE you can read about in the documentation. Once you're signing files, you probably want to verify a file is signed properly. Fortunately, SIGNTOOL.EXE has the verify option you can use to check.
signtool verify /pa <files>
Manually signing your binaries is certainly not going to scale so you'll want to automate the process. For signing .NET assemblies I found an article that talks about how you can use a .PFX file in place of the strong name key (.SNK) file most of us use. As the article says, you'll want to make sure to export the .PFX file without any other certificates by ensure you do not check "Include all certificates in the certificate path if possible." Following all the steps in the article, I copied the exported key over to a new machine, and added the .PFX file. Visual Studio prompted me with the Import Key File dialog asking for the .PFX file password. Typing in the password and clicking OK appeared to work. The problems started when I tried to compile the application. I got the Import Key File dialog again asking for the password, but entering the correct password just got me a message box titled "Error importing key" with the message "Object already exists." Looking through the Certificate Manager, I couldn't find a copy of my certificate anywhere. Wondering if this was an issue because I was running Visual Studio as a regular user, I elevated Visual Studio to have administrator rights and still encountered the same error.
As I started reading about others having similar problems and quickly falling into the bottomless pit of acronyms like OPENSSL, SHA1, PEM, SPN, PVK, and PCKS12, I admit that I gave up. I just want to get my binaries signed, not have to become a super certificate ninja. Since I knew SIGNTOOL.EXE worked, I just needed to wrap it up in an MSBUILD. Looking at the MSBuild documentation, I found the perfectly named SignFile that's part of MSBuild. Sadly, it only works on Portable Executable (PE) files and won't sign your .MSI files. Equipped with the Exec task in MSBuild, you can pretty much get anything wrapped up quickly:
<Error Condition="'$(PrivateKeySignFile)' == '' "
Text="PrivateKeySignFile property not set for PrivateKeySignTask"/>
<Error Condition="'$(PrivateKeyPassword)' == ''"
Text="PrivateKeyPassword property not set for PrivateKeySignTask"/>
<Error Condition="'$(PrivateKeyTimestampURL)' == ''"
Text="PrivateKeyTimestampURL property not set for PrivateKeySignTask"/>
<Exec Command="signtool.exe sign /f $(PrivateKeySignFile)
/p $(PrivateKeyPassword) /t $(PrivateKeyTimestampURL)
@(InputPrivateKeySignFiles, ' ')"/>
Since writing MSBuild tasks derived from ToolTask, it'd take about five minutes to make SIGNTOOL.EXE a little easier to use on a larger project.
Now with the reasonably priced digital certificates through TUCOWS, you should take a hard look at signing your binaries and installations. It's not required, but it sure looks better on Vista if you do.
Update May 15, 2008: Microsoft lost the link to my column so I changed the Debugger Chooser link to download the code for that issue of MSJ.