Code Signing: two worlds defined

I've always been a fan of code signing. There's "signing" to give the assembly a strong assembly name, and there's "signing" to verify the application hasn't been tampered with. (It irks me that they're named the same.) It finally gelled in my head the difference between the two. For my own reference, and for the benefit of others, here is a description of each:

Strong Name

Reason: This is necessary to install assemblies into the GAC and to include a library in a signed project. It is specific to managed code.
Benefits: This insures the library doesn't conflict with other dlls. It says nothing about the origin of the file.

Technique (Visual Studio 2005):
- In the project's properties, click on the Signing tab
- Check "Sign the assembly"
- In "Choose a strong name key file" choose New to generate a .snk file
- For other projects using the same .snk file, choose Browse in this dialog, and find the .snk file created previously

I like to use the same .snk file for all projects in a solution. When choosing Browse, it copies the .snk file. I additionally do this:
- Close the solution
- Move the .snk file to a central location, and delete the copies
- Open the project files in my text editor of choice
- Locate the .snk file reference, and modify the path accordingly
- Open the solution and rebuild

Technique (Visual Studio 2003):
- Use sn.exe from a Visual Studio Command Prompt to generate a .snk file ( or use VS 2005 :) )
- In the Assembly Info file in each project, add the path to the .snk file

Gotchas:
- This .snk file should be kept in secret. You can create a public key file using sn.exe worthy of distribution.
- If this is an absolute path into C:\Documents and Settings\User\My Documents\Visual Studio 2005\Projects\... and you check this file into source control, your team won't like you. Please use relative paths.
- VS 2003 only: the compiled code is signed from inside the build directory (e.g. /bin/Debug), so relative references need to start there. I often found I'd have a bunch of "..\..\..\..\.." in my key paths.
- VS 2005 only: the snk file is referenced from the project directory, so relative paths need to start there.

References:
- Using a strong name in .NET
- Demanding a strong name in a library

Verify Origin

Reason: This is necessary for Windows Mobile 5, and good practice. It is not part of managed code, but rather a part of Win32.
Benefits: This documents the binary file hasn't been changed since it was built, and the builder can be trusted. It uses a chain of trust to a central trusted root certificate to insure the author is indeed who they say they are.

For production use, you should buy a certificate from Verisign or another trusted provider. Ramon has suggested a free provider: http://www.cacert.org/. I haven't reached the same level of trust he has, and can't comment on using it though. For testing, you can create a "self certificate". It doesn't tie to a trusted root certificate, but can be installed on a client machine as a trusted source.

Technique:
- From a Visual Studio Command Prompt, do this once:
makecert -r -sv app.self.pvk -n "CN=AppCert" -b 01/01/2000 -e 12/31/2050 app.self.cer
pvk2pfx.exe -pvk app.self.pvk -spc app.self.cer -pfx app.self.pfx
Substitute "app.self" and "AppCert" in both commands for what ever descriptive info you'd like.
Modify the beggining (-b) and ending (-e) dates as necessary.
Use MSDN or makecert -! for other parameters.

- After building the project each time (and signing for strong naming), run this command:
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\signtool.exe sign /f ../../../path/to/app.self.pfx /d "Descriptive App" /du http://www.tempuri.org/ app.exe
Substitute "app.self" for the actual .pfx file, and other info with info relative to your app and your organization.
I like including this as a post-build event on the solution.
An NAnt task would also be a great place to put this command.

Gotchas
- These .pvk, .cer, and .pfx files should be kept in secret. Handing them out defeats the purpose.
- Post-build events are run from the build directory (e.g. /bin/Debug), so relative paths have to start from here

References:
- Sign your redistributables quick and easy
- Signing assemblies for Windows Mobile 5


Conclusion

With both of these in place, you can look at an exe or dll and know that:
- It is uniquely named
- It is unaltered since it was built and the builder can be trusted

The other point of note: .snk sign first, .cer sign second. .snk is .net specific, .cer is bigger than that.

Rob

NAnt intellisense in Visual Studio

NAnt is a phenomenally cool tool for automating build scripts. Coding NAnt build files feels natural to me: unix shell script style functions and xml style syntax. However, getting all the parameters just so is a bit intense.

Visual Studio can provide intellisense for NAnt, if it has an xsd file to use for reference. NAnt comes with an nant.xsd, and some pretty good docs for installing it. This is great for NAnt tasks, but doesn't handle NAntContrib's features.

Clint describes a technique here and here for using NAnt to build the nant.xsd file. He was using an older version of NAnt though, so I needed to modify Clint's code slightly. While I was in there, I grabbed other dlls in the nant bin folder too.

Here is a zip file with a .build file, a .reg file, and the resulting nant.xsd it builds. The build file builds the nant.xsd, and copies nant.xsd into the correct spot in Visual Studio. The registry key tells Visual Studio it's there.

The build file assumes you're using NAnt v. 0.85 release. If you're not, grab the xmlns reference from the top of the original nant.xsd provided in the NAnt install, and copy it into the build file.

To get intellisense in Visual Studio, run the build file, and load the registry key. Restart Visual Studio, and you're golden.

Clint and others have discussed creating a Visual Studio template file, so you could add a new file of type "NAnt Build File" from within Visual Studo. Since I'm usually copying a build file from another project as a starting point, I haven't found the need to sit down long enough to figure this out.

Rob