One feature that will start to show up on the latest CTP of Whidbey is test key signing -- basically delay signing++.  Lets do a quick review of what delay signing is, and then see where test key signing takes over.  Recall a delay signed assembly is one which has a public key associated with it, however its strong name signature is simply a block of 0's.  Since that block of 0's is unlikely to be the correct signature for the assembly, delay signed assemblies are registered for skip verification with the sn -Vr command.  This command allows the assembly to load even though it does not have the correct signature bytes.

One problem with this is that it opens up a hole on the machines with these skip verification entries.  There is no restriction on who can create the delay signed assemblies -- a delay signed assembly created by a developer on the CLR team looks the same as a delay signed assembly created by a malicious person on the Internet.  Both can create an assembly that has the Microsoft public key, a zeroed signature block, and both will be treated the same by anyone who has the skip verification entries setup for the Microsoft key -- which turns out to be most of the team working on the CLR and framework libraries.  Since these assemblies are granted FullTrust by policy, you can see the issue.

The same issue applies basically anywhere delay signing is used.  Developers and testers have skip verification entries for trusted assemblies on their machines, and nothing prevents other parties from creating assemblies that look to those machines as if they came from the build process.  The problem is mitigated by placing strong name codegroups below a zone code group in policy, but in general still remains.

Enter test key signing.  A test key signed assembly is similar to a delay signed assembly in that it allows the assembly's signature and public key to be mismatched.  However, a test signed assembly actually has a valid signature -- one created with a separate test key pair.  When an assembly is test key signed, it still needs to use sn to register a test key for the assembly.  This registration says "when loading this assembly, verify its signature against this public key, not the one specified in the assembly identity."  In effect, you get the same benefits of delay signing, with the added feature that only people with access to the test signing key can create assemblies that can pretend to have your public key.

In order to use test key signing, you first delay sign your assembly as normal.  For the VB and C# compilers this means something along the lines of:

csc /out:assembly.dll input files ...  /keyfile:publicKey.pk /delaysign+

Now you have a standard delay signed assembly.dll.  Dumping the signature shows that it is the expected block of zeros:

Strong name signature (128 bytes):
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0

The next step is to test key sign it:

D:\src>sn -TS assembly.dll testKey.snk
Microsoft (R) .NET Framework Strong Name Utility Version 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.

Assembly 'assembly.dll' successfully re-signed

At this point assembly.dll has the public key of publicKey.pk, but a signature that is computed with testKey.snk.  Note that the key size of publicKey.snk and testKey.snk must match, or the test signing operation will fail with the message "Key pair does not match public key from assembly".  If we use the signature dumping code, then we'll see that it is no longer all zeros:

Strong name signature (128 bytes):
31 79 de c8 9c c3 5c 19 e5 5b 4b 66 65 53 ef 6d
89 45 77 b9 ba f4 81 56 d2 5a ab 7b  9 f8 a3 14
79 9a 38 f5 cb af 7f e9 f8 78 d4 24 57 27 a4 c0
e7 42 54 e1 a7 69 51 33 2e 3b 84 56 17 b6 78 4c
82  d 45 83 a9 6a 1e  5 77 f0 88 6e 89 91 88  e
89 a1 cd 7a 54 75 26 35 69 74 75 6f b1 63 5a 63
ec 8b  2 6c  c 15 f1 9a  d 20 75 a3 89 31 82 22
1b  8 86 3c fd 20 9c b8 1d 34  a  a e2 6a f4 8f

Now we need to extract the public key from the test key, and set up a test key registration for this assembly:

D:\src>sn -p testKey.snk testPublicKey.pk

Microsoft (R) .NET Framework Strong Name Utility Version 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.

Public key written to testPublicKey.pk

D:\src>sn -Vr assembly.dll testPublicKey.snk

Microsoft (R) .NET Framework Strong Name Utility Version 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.

Verification entry added for assembly 'assembly,B77A5C561934E089'

Assembly.dll is now fully test signed and ready to use as if it were signed with publicKey.pk.  Note that you need to register the test public key only, attempting to register the full keypair will result in the message: "The public key supplied for test signing is invalid".  An * can also be used for the assembly name, if you supply the corresponding public key token, this works in the same way that the * wildcard works for delay signing.  Notice also that running sn -v on the assembly shows that it is valid while sn -vf indicates that it is either delay signed or test signed. 

In addition to the commands shown here, a few other sn commands got updated to support test key signing.  There is a new -TSc option to test sign using a key container instead of the key file that -TS requires.  sn -Vl will now show test signed assemblies and the public key they are signed with.  sn -Vu and -Vx will also remove test key signatures for the given assembly.  Finally, sn -R will also resign a test key signed assembly.

Test keys can be managed in a few ways.  One option is to create a test signing key and check it into the source control system with the rest of the code, next to the official public key.  You can then periodically change this key in the source control system.  This has the advantage that developers can generally just create a new enlistment in your source control and everything is ready to build right away.  The downside is the usual problems with checking in a key pair.  (this is mitigated somewhat by the fact that you are changing this key pair periodically and that it is not the actual official pair).

Another option would be to have developers simply create a key on their own machines.  The downside here is that there is a step that everybody must do before they can build the code, and that there is no central way to force individual developers to update their key every now and again.

[Updated 11/4/2005: fixed the keyfile to be registered]