In today’s post, I’ll be discussing the use of Authenticode to sign software programs; this post will be of interest primarily to software developers. Large software companies (like Microsoft) often have an entire team dedicated to the code-signing and release process, but even (especially) small software publishers should sign their code. In this post, I’ll explain why, and tell you everything you need to do to achieve the benefits of shipping signed code.
Why sign your code?
As a software publisher, there are two reasons to sign your code:
- To prove its Integrity
- To develop its Reputation
The first point is simple: digitally signing your code helps to ensure that it cannot be tampered with, either on your servers, or when it is being downloaded to a user’s computer, especially over an insecure protocol like HTTP or FTP. This provides the user the confidence of knowing that the program they’ve just downloaded is the same one that you built.
Of course, that Integrity alone doesn’t mean a lot. Malicious files can also be signed, and a signature from, say, Bad-Guys-R-Us doesn’t mean that the code is safe to run. That’s where Reputation comes in. Historically, major software publishers like Microsoft, Adobe, Apple, IBM, etc, have worked hard to develop a good reputation in the minds of users. A user who downloads an application signed by Microsoft is usually more likely to trust and install that program than if the program were unsigned, or signed by some company they’ve never heard of. One problem with this scheme is that it doesn’t work too well except for the biggest of publishers—if I’ve never heard of Just Great Software, should I trust a package that bears their signature?
Internet Explorer 9’s SmartScreen Application Reputation feature helps level the playing field. This feature uses a variety of signals to evaluate the reputation of a given download, including the download history and popularity, anti-virus results, reputation of the site it has been delivered from, and more. As a small software publisher, the best way to accumulate your good reputation and allow it to benefit all of your software is to digitally sign your code. Signing your code allows the SmartScreen Application Reputation service to recognize a program’s origins, and allow that origin information to influence the reputation of the program. Small publishers benefit the most from this. For instance, while most users have never heard of me, my freeware programs are digitally signed by my certificate, and the clean reputation for my certificate means that SmartScreen Application Reputation can identify them as non-malicious.
When SmartScreen recognizes non-malicious code, the user benefits from a more streamlined trust experience, and fewer security prompts are shown when downloading and running the program. In contrast, unsigned and unknown programs are treated with suspicion and show more security warnings; our data indicates that 25-40% of such programs are eventually determined to be malicious.
Of course, if I were to ever abuse my good reputation to sign and release malicious code, the SmartScreen system can easily revoke my good reputation—my certificate’s signature would turn from a badge of honor into a flashing signal of untrustworthy software.
Hopefully, I’ve convinced you that signing your code is the right way to go. Now, on to the “how-to” portion of this post.
Step 1: Acquire a Software Publisher’s Digital Certificate
The first step is to get a software publisher’s certificate. Internally, these certificates are slightly different than a HTTPS server certificate (they bear different usage flags), and often cost a bit more because the certificate authority will perform more due diligence in verifying your identity. Certificates are issued by Certificate Authorities (CAs), firms whose job it is to verify the identity of certificate requestors and issue cryptographically-protected certificates that map the private key (which only you know) to a public key (which is contained in the certificate itself).
I purchased my personal Software Publisher’s certificate from Comodo via TuCows, a reseller. Their current prices are $75 for a certificate valid for one year, $140 for two years, or $195 for three years. Generally speaking, it’s a good idea to buy a certificate with the longest possible validity period because renewing certificates is not a fun experience, and it also helps to mitigate the problem of certificate rollover. Certificate rollover occurs when your old certificate expires and you begin signing your code with a new replacement certificate; all of your reputation was accumulated against the old certificate, and hence there may be a time lag for your new certificate to acquire a good reputation.
The process of acquiring a certificate typically takes a few days, and for non-incorporated software publishers like me, requires a fair amount of personal information. For instance, the validation process required that I fax a copy of my drivers license and a few utility bills to the Certificate Authority, so there was reasonable proof of my identity. I also validated my phone number and spoke to a representative. If I were to ever “go rogue” and start using my certificate for evil, I’m sure the terms of service say that this information would be provided to law enforcement so they could come ask me some questions.
After the verification process was completed, I was given the opportunity to download my new certificate. When downloading your new certificate, you should follow the Certificate Authorities instructions exactly as there are some mistakes that can be very difficult to recover from. In particular, choose a memorable but strong password to protect your private key file. After you have your certificate, be very sure to protect the private key file—if you lose control of your private key, a bad guy could sign code using your certificate. If your certificate is used maliciously, bad reputation will taint everything you’ve ever signed!
Note: Yes, you can also generate a self-signed certificate, but this is only useful if your software will never be used outside of your organization. Inside your organization, you could use Group Policy to deploy your self-signed certificate to all clients so that they trust it. However, any PC that isn’t configured to trust your certificate will block your software as bearing an invalid signature. Unless your company already has an internal PKI (public key infrastructure) deployment, you’re better off getting a publisher certificate that chains to one of the Trusted Root CAs.
Note: In August 2012, Microsoft announced support for a new type of Code-Signing certificate, the Extended Validation (EV) certificate. These certificates tend to be more expensive and harder-to-use (requiring security token hardware) but have the benefit of providing faster accumulation of reputation for SmartScreen.
Step 2: Sign your code
After you have a certificate, you can begin signing your installation executables or MSI install packages. Because you’ll want to do this for every build that you release, automating as much of the signing process as possible using a script or batch file is highly recommended.
Note: The .NET Framework has a different type of code-signing called “Strong Naming”. A strong name is not recognized by anything in Windows except the .NET Framework, and hence I won’t discuss it further here. ShawnFa wrote a good article explaining Strong Names and Authenticode.
To sign your program using Authenticode, you can use the SignCode.exe utility which shipped with the Microsoft .NET Framework version 1.1:
You’ll be prompted to enter the password for your PVK file, and after doing so, your program will be signed and time-stamped.
The –n parameter specifies the string that will be shown in the “Name” field identifying the software. The –i parameter specifies the URL that will be launched if the user clicks on the Name hyperlink. The –a parameter specifies which hash algorithm should be used—this should always be sha1 because older hash algorithms are less secure, and will eventually be retired. Internet Explorer on Windows 7 SP1, for instance, disables MD2/MD4 hashes and treats signatures using those algorithms as invalid. The –t parameter specifies the URL of the time-stamping server, discussed later.
These inputs result in a signature that is displayed by various trust prompts like so:
Alternatively, you can use the SignTool.exe shipped in the Windows SDK and later versions of the .NET Framework. To use this tool, you’ll need to convert your .SPC & .PVK files into a new PFX file, which you can do from a Visual Studio Command prompt:
pvk2pfx -spc mycert.spc -pvk mykey.pvk -pfx mycert.pfx -pi PVKPassword -po NewPFXPassword
After that, you can use a script like the following to sign your package:
set /P PFXPass=Enter PFX Password:
signtool sign /p %PFXPASS% /f C:\src\mycert.pfx /d "FiddlerCap" /du "http://www.fiddlercap.com/" /t http://timestamp.comodoca.com/authenticode /v FiddlerCap-en.msi
Best Practice: Sign both the installer and the application
When downloading installation packages from the Internet, the browser and/or Windows Shell will only check the digital signature on the installer itself. However, as a best practice, you should also sign the main executable of your application as well. This helps prevent tampering, but more importantly, it helps ensure that any security tools on the user’s machine can more readily identify your code. For instance, many anti-malware or firewall tools will treat unsigned executables with suspicion, and may even block them if they happen to share the same filename as a malicious program. For instance, one of my utilities, SlickRun shared the same filename (sr.exe) as a malicious program, and some anti-malware tools were too primitive to recognize the false positive. However, after I signed sr.exe directly, this problem went away. Similarly, some firewalls assign exceptions to programs based on their digital signature or file hash. If the user approves an exception to allow your program through the local firewall, that exception may be deleted if your program is later updated and the file’s hash changed. Signing your code can help prove to the firewall that the new version of your program should inherit the exemption granted to the older version.
Note: Typically, Windows does not itself check the digital signature when running a locally-installed version of your program; it only checks the signature when the program bears a Mark-of-the-Web indicating that it was downloaded from the Internet or extracted from an archive downloaded from the Internet. However, executables written in .NET can be an exception to this. The .NET Framework has the ability to assign security permissions to code based on its signature, called “publisher evidence.” Doing so necessitates that the signature be verified, and verifying the signature may require an expensive network request to check the certificate for revocation. If you are not using the “publisher evidence” feature of .NET, you can modify your application’s manifest to indicate that .NET should not check the signature.
Best Practice: Time-stamping
When signing your code, you have the opportunity to timestamp your code; you should definitely do this. Time-stamping adds a cryptographically-verifiable timestamp to your signature, proving when the code was signed. If you do not timestamp your code, the signature will be treated as invalid upon the expiration of your digital certificate. Since it would probably be cumbersome to re-sign every package you’ve shipped when your certificate expires, you should take advantage of time-stamping. A signed, time-stamped package remains valid indefinitely, so long as the timestamp marks the package as having been signed during the validity period of the certificate.
Thanks for helping ensure a secure and streamlined experience for Windows users!
Update: Not all publisher certificates are enabled to permit timestamping to provide indefinite lifetime. If the publisher’s signing certificate contains the lifetime signer OID (OID_KP_LIFETIME_SIGNING 18.104.22.168.4.1.322.214.171.124), the signature becomes invalid when the publisher’s signing certificate expires, even if the signature is timestamped. This is to free a Certificate Authority from the burden of maintaining Revocation lists (CRL, OCSP) in perpetuity.
Update: It also appears that some CAs do not provide SPC and PVK files, instead providing the certificate in a different format. You can convert from a .CER file to a SPC file using Cert2SPC.exe in the Windows SDK. If you have a PEM file instead of a .PVK file, you can convert that using OpenSSL's pvk command: pvk -in PEM_KEY_FILE -topvk -out PVK_FILE. http://help.godaddy.com/article/6034 has a step-by-step walkthrough.
Curious about where the Authenticode signature actually goes into the binary? See this whitepaper.
Update: Some developers use tricks to sneak unauthenticated data inside Authenticode-signed binaries. You shouldn't do that.