For Chrome, I had to create a network update facility. This is a pretty simple task on the surface, but it has some interesting security implications. Specifically, what happens if someday my website gets hacked and someone replaces my “patch” with a virus? Then would all my customers auto-upgrade a virus? That would be awful, so I want to protect against that.
Keep in mind, however, that all these other applications you are running on your desktop probably have no security against this. They happily connect up to some server somewhere and download a program. If the right evil-doer gets into that website, who knows what your system might download.
So, how to protect against this? Well, the obvious solution is to sign your code. Signing your code generally uses asymmetric encryption (encryption methods that use a public and private key pair like RSA or ECC).
Microsoft has a technology called Authenticode which they use in Internet Explorer to help you avoid downloading bad programs. (Most users probably read “this code is not authenticated” but click right through to install anyway) But for my purposes, I want to verify a signature within my own code- authenticode doesn’t let me do that easily. And, even if it did, I’d have to go get a certificate from Verisign or Thawte – and that would cost me $150 or more.
So, I came up with the following solution. Thanks to help from CodeProject for a couple of sample source code projects.
The idea is that when my software wants to do an upgrade, it downloads a small XML file from the server which tells the application what new version is available, where to download it from, etc. The XML file also contains a signature section, which was created by signing the entire XML file with my private key.
So, I create a private key/public key pair using Microsoft .NET’s SN.EXE program, and I store that away in a safe place. I extract the public key, and hard code that into my program file which I ship to customers.
When the program checks for updates, it downloads the XML file. It can now verify the authenticity of the XML file by checking that it was signed with my key. Inside the signed portion of the XML is a MD5 hash. The MD5 hash is a hash code for the to-be-downloaded patch. Assuming that the signature of the XML file matched, we will save away this MD5 to compare against the MD5 of the file we actually download.
Now the application proceeds to the downloading step. After that completes, it verifies the MD5. Since the XML file signature matched, I know that this MD5 hash is “approved” by me. And since the MD5 of what I actually downloaded matches the signed XML file, I know I can safely install the file.
Amazingly, in C#.NET, the code for the entire signing/verification process is an executable that is less than 40KB.
The great thing about this approach is that its quite safe and hard to break. I didn’t have to go get a certificate and shell out bucks to anyone.
One risk would be if my public/private key pair was ever stolen or comprimised. If so, I’d have no way to update existing clients. But this is a problem that mostly exists in the real world today. CRLs (Certificate Revocation Lists) can be used when you have a real certificate to find out if a public key that you once used is still valid. But most software doesn’t implement CRL checking anyway I suppose that will change someday.
And I think this is better than Microsoft’s authenticode. Authenticode will still allow the poor user (who didn’t know why he got some funky security warning) to install the code. My approach flat-out-rejects anything which doesn’t pass my signed-code test.
Well, thats my solution. Hopefully I didn’t forget anything silly. And I hope that my software is a lot more secure against downloading bad patches than most of the software out there.