What Happens When You Fully Sign a Test Signed Assembly

When an assembly is test signed, the public key used to verify its signature is different from the public key that makes up part of the assembly identity.  So what happens when you take an assembly which is registered as a test signed assembly on your machine and fully sign it?

The key here (aren't puns fun) is the fully signed bit in the CLR header.  An assembly which is fully signed (so not simply named, test signed, or delay signed) has the COMIMAGE_FLAGS_STRONGNAMESIGNED bit set in the Flags field of the IMAGE_COR20_HEADER.  (Both can be found in corhdr.h in the Framework SDK)

If the CLR is verifying a signature, and it sees this bit set, it won't even attempt to check the skip verification or test sign lists.  Instead, verification proceeds with the public key embedded in the assembly itself.  So the answer to the question is that a fully signed assembly with a entry on the test signed assembly list will work as expected, and verify with the correct public key.

In the SSCLI v2, you can see this behavior in the strong name code located at sscli20\clr\src\VM\strongname.cpp.  Specifically, go to the VerifySignature method -- the relevant code starts at line 2498.  On 2504 we check to see if the fully signed bit is in place, and if not we check for a test public key on 2506.  The magic behind test key signing  is essentially on one line of code, line 2514, where we substitute the test public key for the assembly's real public key.