Thursday, March 02, 2006 - Posts

How To: Strongname Inheritance Demands at Runtime

Yesterday a client of mine had an interesting challenge. He had a sealed class which he needed to “unseal” due to some changes in his project. However he needed to control who could inherit the class and applied a StrongNameIdentityPermissionAttribute with an InheritanceDemand action to the class. He soon learned that the XmlSerializer cannot serialize types with declarative security. This is by design in the .NET framework, since XML serialization is achieved through runtime generated types for performance reasons. A common workaround is to apply imperative security in lieu of declarative security. However, since InheritanceDemand is a load time security assertion, this was not a feasible option for my client.
The solution to the challenge was to recreate the inheritance demand action in the class’ constructor as shown below.
public abstract class InheritanceDemandingClass
{
    protected InheritanceDemandingClass()
    {
        byte[] myPK = typeof(InheritanceDemandingClass).Assembly.GetName().GetPublicKey();
        byte[] callingPK = Assembly.GetCallingAssembly().GetName().GetPublicKey ();
        if (callingPK==null || myPK.Length!=callingPK.Length)
        {
            throw new SecurityException("The calling assembly does not have permission to create this type.");
        }
        for (int i = 0; i < myPK.Length; i++)
        {
            if (myPK[i]!=callingPK[i])
            {
                throw new SecurityException("The calling assembly does not have permission to create this type.");                 
            }
        }
    }
}

The above code compares the calling assembly’s public key with the class’ public key and throws a SecurityException if the two assemblies aren’t signed with the same key. This simple solution should be sufficient for most scenarios, as the common usage for inheritance demands is to ensure that only your types can extend your types. However the example can easily be extended to support other keys or public key tokens as well.
There are some differences with this approach and using declarative security; the type can be reflected since the security assertion happens at runtime, and you cannot use permview.exe to see what demands the type makes. If imperative security was applied you would still have both of these issues.