Occasionally we run into a scenario where someone asks about shipping a strong name skip verification entry for their assembly with their product. Generally, their reasoning is that the performance hit of strong name verification is too great for their application.

Regardless of the reasoning, you should never ship a skip verification entry. The strong name skip verification list is a tool to help developers write strongly named code without having to provide each developer with access to the private keys. On non-developer machines, including any machines used for official build signoff test passes and end user machines, there should be no entries on the list.

By having an entry on the skip verification list for an assembly, anyone will be allowed to tamper with that assembly and still have it retain its identity. Further, anyone can simply replace the assembly with one of their own which claims to be the official assembly. Even if this is not done in a malicious way, it still can create support issues – there is no way of knowing which bits are on the user’s machine anymore. Are they the officially shipped ones, or are they modified versions which were updated by a third party vendor who was adding onto the application?

If after explaining this , the product still wants to ship with skip verification entries, I recommend that they simply not strongly name their assembly to begin with. If they’re not depending on being able to rely on their assembly’s identity, and they don’t care if others tamper with it, then strongly naming it isn’t buying them anything -- and the cost of verifying the signature is not worth paying.

On the other hand, if the application is making use of features provided by strong names, then I make a different recommendation. First: measure, measure, measure. If, after measuring, it turns out that strong name verification is in fact preventing the application from hitting its startup goals, then I recommend slightly restructuring it into a stub executable and an assembly with most of the logic that used to be in the main entry point.

Once the application is factored so that the executable contains nothing but a Main which calls into the real entry point in the second assembly, you can install that second assembly into the GAC. Since assemblies in the GAC do not have their strong name signature verified at load time, none of the code in this library will incur the cost of verification … leaving only the much smaller stub exe that needs to be loaded and hashed. This technique can reduce strong name verification time dramatically, depending on the size of the application code that was moved into the GAC.

A few quick notes on this: Since the assembly is not in the GAC in order to be shared across applications, and it certainly wasn’t tested to be attacked by partially trusted callers, it should not be marked with the AllowPartiallyTrustedCallersAttribute. In fact, since the assembly is logically the entry point of the application and probably doesn’t have any usable surface area for anything outside of the stub exe, it might make sense to have no public surface area in the assembly at all. Simply make the entry point an internal class, and declare the stub exe as a friend assembly using the InternalsVisibleTo attribute.

I tend to see this scenario most often at the very end of product cycles, when the assemblies are no longer delay signed and are now being tested with full signatures. As you can imagine, this type of refactoring as a product is getting ready to ship is not generally something that product groups want to do. This is another good reason that products should be developed using test key singing instead of delay signing. With a test key signature, assemblies are still verified at load time -- a delay signed assembly is never verified. This means the startup characteristics of a test signed assembly more closely match those of a fully signed assembly, and this performance problem does not show up at a point in the product cycle when it’s too late to address.