Easily Creating a StrongNameMembershipCondition for an Assembly

Taking a break from sandboxing in an AppDomain for a minute, lets take a look at another aspect of policy.  One situation that comes up very frequently when trying to execute code in a limited-trust sandbox is that there are some assemblies that you do trust, however they're being limited by the sandbox.  The best way to allow these assemblies the trust that they need is to create a code group that matches their strong name, and grant that group a higher trust level.

However, creating the strong name membership condition can be tricky, since you need to know the public key of the assemblies involved, and getting that into your code isn't necessarily the easiest thing in the world.  Because of this, lots of people fall back to trusting all code from a specific site, or abandon the sandbox idea all together.

It turns out that reflection exposes all the information you need to easily build up a StrongNameMembershipCondition for a given assembly.  In fact, if you're willing to deal with the slight performance hit that you'll take for using reflection, this is generally the easiest way to create the membership conditions.  It insulates you from having to get the public key value into a byte array, updating that array whenever your key changes, etc.

The code to do this is very straightforward:

/// <summary>
/// Create a StrongNameMembershipCondition that matches a specific assembly
/// </summary>
/// <exception cref="ArgumentNullException">
/// if <paramref name="assembly"/> is null
/// </exception>
/// <exception cref="InvalidOperationException">
/// if <paramref name="assembly"/> does not represent a strongly named assembly
/// </exception>
/// <param name="assembly">Assembly that will match the strong name membership condition</param>
/// <returns>A membership condition that matches the given assembly</returns>
public static StrongNameMembershipCondition CreateStrongNameMembershipCondition(Assembly assembly)
{
    if(assembly == null)
        throw new ArgumentNullException("assembly");

    AssemblyName assemblyName = assembly.GetName();
    Debug.Assert(assemblyName != null, "Could not get assembly name");
        
    // get the public key blob
    byte[] publicKey = assemblyName.GetPublicKey();
    if(publicKey == null || publicKey.Length == 0)
        throw new InvalidOperationException(String.Format("{0} is not strongly named", assembly));

    StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);

    // and create the membership condition
    StrongNameMembershipCondition mc = new StrongNameMembershipCondition(
            keyBlob, assemblyName.Name, assemblyName.Version);

    Debug.Assert(mc.Check(assembly.Evidence), "Did not generate a matching membership condition");
    return mc;
}

In order to use this, just pass the Assembly that you'd like a membership condition to match into the method, and you'll get a membership condition back out, as long as the original assembly was strongly named.

One of the more common usage scenarios is to call this method in order to create a strong name membership condition that matches yourself.  Adding a simple overload to this method simplifies this case, and allows that membership condition to be created easily.

/// <summary>
/// Create a StrongNameMembershipCondition that matches the calling assembly
/// </summary>
/// <exception cref="InvalidOperationException">
/// if <paramref name="assembly"/> the calling assembly is not strongly named
/// </exception>
/// <returns>A membership condition that matches the calling</returns>
public static StrongNameMembershipCondition CreateStrongNameMembershipCondition()
{
    return CreateStrongNameMembershipCondition(Assembly.GetCallingAssembly());
}

Tomorrow -- back to sandboxed AppDomains.