Combining Strong Names with Authenticode
If you want to use both a strong name and Authenticode signature on your assembly (for instance if you need a strong name for strong assembly identity, and your company has a rule requiring Authenticode signatures on all shipped products), then you need to make sure to do these in a specific order.
- Strong name the assembly
- Authenticode sign the assembly
The reason for this is that since Authenticode signatures were invented before strong naming was a twinkle in someone's eye, they don't know anything about strong name signatures. However, the CLR does know about both signature types, and can therefore make sure that signatures are applied in a manner that allows both to validate.
Why does the CLR have to do anything at all to allow both signatures to validate? Imagine for a minute that no extra work is done in the dual-signature case, and that we just hash and sign the assembly. When you strong name sign the hash is of the assembly with no signatures; however the Authenticode signature will be with the hash of the assembly containing the strong name signature. During verification, the problem appears -- when verifying the strong name signature the hash of the assembly is different than the one calculated during signing, because the Authenticode signature is now part of the assembly. If we attempt to fix this by resigning the assembly after Authenticode signature is applied the reverse is now true -- the hash of the assembly with the original strong name signature (which is what the Authenticode signature contains) is now different from the hash with the new strong name signature.
In order to prevent this cycle, when the hash of an assembly is calculated the CLR actually zeros out the directory entry in the optional headers of the PE file for the Authenticode signature, and will skip over the section of the file containing the Authenticode signature itself. This means that the hash used for the strong name signature does not include any Authenticode information at all. Since you should always strong name sign first, this step actually does nothing during the signing stage because there will not be an Authenticode signature to skip. However, during the verification process there will be an Authenticode signature present . By zeroing out the directory entry and skipping the section of the PE image containing the Authenticode signature the hash will be the same as it was at signing time -- therefore allowing the strong name signature to verify.
Since Authenticode doesn't know anything about strong names, it does not treat the strong name signature in any sort of special way. That's why it needs to be applied after the assembly is strong name signed, since it needs to see the exact same bits during signing and verification. Note that this means that if you're delay or test key signing, you need to apply the Authenticode signature after the final signature is calculated, not just after the assembly is built.
Incidentally, the Authenticode signature is not the only section of the PE file that is not covered by the strong name signature. We also skip the checksum field of the PE header and the strong name signature blob.
Comments
Anonymous
January 15, 2007
Not directly related to this post, but... As the source of all useful and up-to-date information on CLR security, do you have any plans for a posting on the effect of IE7 on CAS etc? I was investigating the NetworkCodeGroup ‘same site’ WebPermission behaviour in the Internet and Intranet zones, and only managed to get it to work in the latter zone after poking and prodding IE7. Needing to enable “Intranet Settings” apparently... I discovered that by luck on loading a HTML page in that zone and the information bar prompting me... Do you know if that’s the only effect installing IE7 has? Alan BTW I never got it to work in the Internet zone... Is there any way to find which rights have been granted to a running app? In those zones an app it can’t read its own rights of course.Anonymous
January 17, 2007
Hi Alan, I haven't thought about doing an IE7 post, but basically we rely on IE to map zones and we rely on zones in default policy as you noticed. I don't know all the details on the changes to IE7's zone mapping policy, but I do know that they default to Internet if they don't know what to do, and that they're much more strict in IE 7. Apps can't self-discover their zone at that trust level as you notice (outside of heuristics like doing various demands and noticing what succeeds). The easiest way to figure this out would be to attach a debugger and look at the AppDomain Evidence for the entry domain. (Or use the IE 7 browser as you did in your example). -ShawnAnonymous
January 18, 2007
http://blogs.msdn.com/shawnfa/archive/2007/01/10/combining-strong-names-with-authenticode.aspxAnonymous
January 18, 2007
Great post. I think there is much confusion between "code signing" and "strong naming". There's also a great post about it here: http://www.robrich.org/archive/2006/11/29/Code-Signing-two-worlds-defined.aspxAnonymous
January 20, 2007
It kills me that the names for these processes are "Code signing" and "Strong Name signing". So thisAnonymous
January 22, 2007
Thanks Shawn. Yup, given that this is solely down to the change in IE7's Zone behaviour, it would be a short post here. Unfortunately I can't find it documented anywhere, so anyone else will have to discover the solution independently. :-( I can guess that the IE blog people might say, oh that's a .NET issue... Anyway, maybe these comments might be findable in google. :-) I'll try a attaching a debugger when I have a look at this again. Thanks. Alan