[ Team LiB ] Previous Section Next Section

6.2 Programming Evidence

In the normal course of application development, you have little need to work directly with evidence; the default evidence supplied by the runtime is sufficient to correctly drive the policy resolution process. If you do need to base runtime decisions on the evidence of an assembly, you'll most likely do so using identity permissions.

In the following sections, we show you how to use the advanced .NET support for directly manipulating evidence, which you will need when performing any of the following tasks:

  • Dynamically loading or creating assemblies at runtime

  • Creating application domains in which to isolate assemblies

  • Developing a custom runtime host

  • Developing custom evidence classes

6.2.1 Introduction to Evidence Programming

The runtime establishes the identity and grant set of an assembly when the assembly is loaded. You cannot alter the identity of an already loaded assembly to change the permissions granted to it. Therefore, you must provide all evidence at the time you load the assembly. Note that the runtime loads each assembly only once into a given application domain. Subsequent load requests result in the runtime using the already loaded assembly. If you try to reload an already loaded assembly but alter its identity by specifying additional items of evidence, the runtime will throw a System.IO.FileLoadException.

To provide evidence when you load an assembly, your code must have the ControlEvidence permission.

If you do not have the ControlEvidence permission, the runtime will throw a System.Security.SecurityException when you try to load the assembly. You can use permission requests to ensure that the runtime will not attempt to execute your code unless it has the ControlEvidence permission, or you can simply attempt to load your assembly and be prepared to handle the SecurityException that will occur if you do not have it.

In order to provide your evidence, you must create the set of evidence objects and add them to a System.Security.Policy.Evidence collection. You then pass the Evidence collection as an argument to the method that loads the assembly. Your evidence takes precedence over the default evidence provided by the assembly loader. When specifying the evidence, you can provide both host and assembly evidence. However, given the limitations of assembly evidence outlined earlier in Section 6.1.1, there is little value in providing anything but host evidence, and so that is where we will focus our discussions.

You can add as many evidence types as you want to the Evidence collection, but only the last one of each type affects the policy resolution process. If we add two pieces of Url evidence to an Evidence collection, the first being http://www.oreilly.com and the second being http://www.somecompany.com, then the permissions for the assembly will be based on the http://www.somecompany.com evidence.

6.2.2 Using the Evidence Class

The System.Security.Policy.Evidence class is a specialized collection that contains two sets of evidence objects: a collection of host evidence and a collection of assembly evidence. The Evidence class has three constructors, as shown in the following declarations:

# C#

public Evidence(  );

public Evidence(Evidence evidence);

public Evidence(
    object[] hostEvidence, 
    object[] assemblyEvidence
);

# Visual Basic .NET

Public Sub New(  )

Public Sub New(ByVal evidence As Evidence)

Public Sub New(
    ByVal hostEvidence(  ) As Object, _
    ByVal assemblyEvidence(  ) As Object _
)

The first constructor creates an empty Evidence object. The second constructor takes an existing Evidence object and makes a copy of it. Note that this is a shallow copy, meaning that the new Evidence collection references the same evidence objects contained in the source Evidence collection; no new evidence objects are created. This is not an issue when using the standard evidence types because they are immutable. The third constructor takes two Object arrays: the hostEvidence argument contains the evidence objects for the host evidence collection and the assemblyEvidence argument contains the evidence objects for the assembly evidence collection.

The Evidence class implements the System.Collections.ICollection collection to facilitate the manipulation of the evidence objects it contains. In addition, Evidence implements members that support direct manipulation of the host and assembly evidence subcollections. Figure 6-2 illustrates the structure of the Evidence class and shows the key methods you use to work with contained evidence elements.

Figure 6-2. Structure of the Evidence class
figs/pdns_0602.gif

Table 6-2 summarizes the members of the Evidence class; the members that require your code to have the ControlEvidence permission are indicated in the far right column titled "C".

Table 6-2. Members of the Evidence class

Member

Description

C

Properties

 

Count

Gets the total number of evidence objects in the Evidence collection.

 

IsReadOnly

Always returns false because .NET does not (currently) support read-only evidence sets.

 

Locked

Gets or sets the value indicating whether Evidence is locked. ControlEvidence is required to set this property to false.

Methods

 

AddAssembly

Adds an evidence object to the assembly evidence subcollection.

 

AddHost

Adds an evidence object to the host evidence subcollection. Requires the caller to have the ControlEvidence permission when Locked is true.

CopyTo

Copies all of the contained evidence objects to an array.

 

GetAssemblyEnumerator

Returns an IEnumerator for enumerating across the assembly evidence subcollection.

 

GetEnumerator

Returns an IEnumerator for enumerating across the entire evidence collection.

 

GetHostEnumerator

Returns an IEnumerator for enumerating across the host evidence subcollection.

 

Merge

Merges the specified Evidence collection into the current collection. Requires the caller to have the ControlEvidence permission when Locked is true and the Evidence collection contains host evidence.

6.2.3 Using the Standard Evidence Classes

The evidence objects you will most commonly use to define the identity of your assemblies are the seven standard evidence classes from the System.Security.Policy namespace:

  • ApplicationDirectory

  • Hash

  • Publisher

  • Site

  • StrongName

  • Url

  • Zone

Each of these classes is relatively simple and independent; they do not extend a common base class (other than System.Object), nor do they implement a common interface. However, their designs all follow a similar pattern, resulting in the following commonalities:

  • All of the classes are marked as sealed in C#, or NotInheritable in Visual Basic .NET, ensuring that malicious code cannot subclass from them to manipulate CAS.

  • All classes are serializable through the application of the System.SerializableAttribute attribute (the Hash class also implements the System.Runtime.Serialization.ISerializable interface). Being serializable is a key requirement of evidence classes.

  • The content of all of the classes is immutable once it is created.

  • All of the evidence classes except Hash implement a Copy method that creates a clone of the evidence object.

  • Most of the evidence classes override the following members inherited from System.Object to base the result on the content of the evidence object:

    Equals

    All evidence classes except the Hash class perform equality evaluation based on the value of the evidence and not on object references.

    GetHashCode

    All evidence classes except the Hash class return a hash code based on the value of the evidence.

    ToString

    All evidence classes override ToString to return a string containing an XML representation of the evidence object's content.

The following sections discuss each of the evidence classes in detail and demonstrate how to use them.

6.2.3.1 The ApplicationDirectory class

The System.Security.Policy.ApplicationDirectory class contains a URL that represents the root installation directory of an application. ApplicationDirectory evidence is unique amongst the standard evidence classes in that the runtime does not evaluate it in isolation. If an assembly has ApplicationDirectory evidence, the runtime also looks for Url evidence to determine if the Url evidence represents a child location specified in the ApplicationDirectory evidence. This will become clearer when we discuss membership conditions and policy resolution in Chapter 8.

The ApplicationDirectory class constructor shown takes a System.String argument specifying the URL of the application root:

# C#

public ApplicationDirectory(String name);

# Visual Basic .NET

Public Sub New(ByVal name As String)

The read-only Directory property returns the URL string used in construction.

6.2.3.2 The Hash class

The System.Security.Policy.Hash class provides evidence based on a hash value of an assembly. A hash is a numeric value calculated using cryptographic algorithms that take the bytes contained in the assembly file as input. The nature of hashing algorithms means that it is very unlikely for the contents of two assemblies to result in the same hash value; even changing a single bit will result in a very different hash value. This means that a hash value provides a unique identity for an assembly (similar to a fingerprint). You can use a hash value to distinguish between two different assemblies, but by itself, a hash does not guarantee the source or integrity of an assembly; this is the purpose of strong names and publisher certificates (see Chapter 2). We provide a detailed discussion of hashing in Chapter 13.

The Hash class is different from other evidence classes in that it provides multiple evidence values (hash values) from a single set of source data. The Hash class constructor takes a System.Reflection.Assembly object that identifies the assembly from which to generate hash values:

# C#

public Hash(Assembly assembly);

# Visual Basic .NET

Public Sub New(ByVal assembly as Assembly)

By default, the Hash class supports two hashing algorithms: MD5 and SHA1. The read-only MD5 property returns an MD5 hash value based on the assembly content, and the read-only SHA1 property does the same but using the SHA1 algorithm.

In addition, the GenerateHash method allows you to compute an assembly's hash using other hashing algorithms. The GenerateHash method takes a System.Security.Cryptography.HashAlgorithm argument containing an object that implements the required hashing algorithm. There are a number of hashing-algorithm implementations provided in the .NET class library (see Chapter 13).

The following code demonstrates the use of Hash to calculate the MD5, SHA1, and SHA512 hash values for an assembly. We use the System.Security.Cryptography.SHA512Managed class to provide the SHA512 hashing implementation:

# C#

using System.Reflection;
using System.Security.Policy;
using System.Security.Cryptography;

public class HashEvidenceDemo {

    public static void Main(  ) {
    
        // Create a new Hash object for the currently executing
        // assembly.
        Hash hashEvidence = new Hash(Assembly.GetExecutingAssembly(  ));
        
        // Use the Hash class to generate hash values for
        // the current assembly
        byte[] md5 = hashEvidence.MD5;
        byte[] sha1 = hashEvidence.SHA1;
        byte[] sha512 = hashEvidence.GenerateHash(new SHA512Managed(  ));        
    }
}

# Visual Basic .NET

Imports System.Security.Policy
Imports System.Security.Cryptography
 
Public Class HashEvidenceDemo
 
    Public Shared  Sub Main(  )
 
        ' Create a new Hash object for the currently executing
        ' assembly. Use fully qualifed name of Assembly class
        ' to avoid conflict with Visual Basic .NET keyword.
        Dim hashEvidence As Hash = _ 
            New Hash(System.Reflection.Assembly.GetExecutingAssembly(  )) 
 
        ' Use the Hash class to generate hash values for
        ' the current assembly
        Dim md5(  ) As Byte = hashEvidence.MD5 
        Dim sha1(  ) As Byte = hashEvidence.SHA1 
        Dim sha512(  ) As Byte = _
            hashEvidence.GenerateHash(New SHA512Managed(  )) 
    End Sub
End Class

Unlike other evidence classes, the Hash.ToString method does not return a representation of the evidence value. Instead, it displays an XML representation of the source from which it calculates the hash values. This means that whenever you call ToString, you get the string representation of the bytes contained in your assembly—this is potentially very large.

6.2.3.3 The Publisher class

The System.Security.Policy.Publisher class provides evidence based on the Authenticode X.509 v3 digital certificate used to sign an assembly. The publisher (producer, author, or creator) of an assembly signs it to prove to consumers that they created the assembly. We discuss signing assemblies in Chapter 2.

Because the Publisher class implements the IIdentityPermissionFactory interface, its presence in the host evidence collection of an assembly causes a System.Security.Permisssions.PublisherIdentityPermission to be included in the assembly's grant set. Refer to Chapter 7 for an explanation of identity permissions.

The Publisher class constructor shown here takes a System.Security.Cryptography.X509Certificates.X509Certificate object that contains the publisher's code-signing certificate. There are many simple ways to create an X509Certificate object, including loading it from a certificate file or extracting it from an existing signed file; refer to the .NET Framework SDK documentation for details:

# C#

public Publisher (X509Certificate cert);

# Visual Basic .NET

Public Sub New(ByVal cert As X509Certificate)

The read-only Certificate property returns the X509Certificate object provided during creation.

The following code demonstrates the creation of Publisher evidence using an X509 certificate contained in a certificate file named C:\MyCert.cer and displays the certificate principal using the GetName( ) method of the X509Certificate object retrieved via the Certificate property:

# C#

using System;
using System.Security.Policy;
using System.Security.Cryptography.X509Certificates;

public class PublisherEvidenceDemo {

    public static void Main(  ) {
    
        // Create a new X509Certificate object from the
        // test certificate file C:\MyCert.cer.
        X509Certificate cert = 
            X509Certificate.CreateFromCertFile(@"C:\MyCert.cer");
        
        // Create a new Publisher evidence object from the
        // loaded X509Certificate object        
        Publisher publisherEvidence = new Publisher(cert);
        
        // Use the Certificate property to get the publisher
        // certificate and display the principal name.
        Console.WriteLine(publisherEvidence.Certificate.GetName(  ));
    }
}

# Visual Basic .NET

Imports System
Imports System.Security.Policy
Imports System.Security.Cryptography.X509Certificates
 
Public Class PublisherEvidenceDemo
 
    Public Shared Sub Main(  )
 
        ' Create a new X509Certificate object from the
        ' test certificate file C:\MyCert.cer.
        Dim cert As X509Certificate = _
            X509Certificate.CreateFromCertFile("C:\MyCert.cer")
 
        ' Create a new Publisher evidence object from the
        ' loaded X509Certificate object        
        Dim publisherEvidence As Publisher = New Publisher(cert) 
 
        ' Use the Certificate property to get the publisher
        ' certificate and display the principal name.
        Console.WriteLine(publisherEvidence.Certificate.GetName(  ))
    End Sub
End Class
6.2.3.4 The Site class

The System.Security.Policy.Site class provides evidence based on the fully qualified host name portion of the URL from where the assembly was loaded (for example, the site from the URL https://www.somecompany.com:8080/dev/HelloWorld.exe is www.somecompany.com).

Because the Site class implements the IIdentityPermissionFactory interface, its presence in the host evidence collection of an assembly causes a System.Security.Permisssions.SiteIdentityPermission to be included in the assembly's grant set. Refer to Chapter 7 for an explanation of identity permissions.

The Site class constructor shown takes a System.String argument containing the name of the site to use as evidence. After construction, the site name is available through the read-only Name property:

# C#

public Publisher (string name);

# Visual Basic .NET

Public Sub New(ByVal name As String)

The Site class also provides the static CreateFromUrl factory method to simplify the creation of Site objects from URL strings. The value of siteEvidence.Name in the following example is www.somecompany.com:

# C#

String url = "https://www.somecompany.com:8080/dev/HelloWorld.exe";
Site siteEvidence = Site.CreateFromUrl(url);

# Visual Basic.NET

Dim url As String = "https://www.somecompany.com:8080/dev/HelloWorld.exe" 
Dim siteEvidence As Site = Site.CreateFromUrl(url)

The runtime does not provide Site evidence for assemblies loaded from file protocol URLs such as file://C:\Dev\HelloWorld.exe. CreateFromUrl will actually throw a System.ArgumentException if you pass it such a URL.

6.2.3.5 The StrongName class

The System.Security.Policy.StrongName class provides evidence based on the strong name of an assembly. A strong name provides the assembly with a unique versioned identity and is a guarantee of the integrity of an assembly. However, a strong name does not guarantee the integrity of the source of an assembly, which is the purpose of publisher certificates. We discuss assembly strong names and publisher certificates in Chapter 2.

Because the StrongName class implements the IIdentityPermissionFactory interface, its presence in the host evidence collection of an assembly causes a System.Security.Permissions.StrongNameIdentityPermission to be included in the assembly's grant set. Refer to Chapter 7 for an explanation of identity permissions.

The StrongName class constructor takes three arguments:

  • A StrongNamePublicKeyBlob object that represents the public key information for a strong name. The StrongNamePublicKeyBlob class is a simple utility class from the System.Security.Permissions namespace used to facilitate the passing of public key information. See the .NET Framework SDK documentation for complete descriptions

  • A System.String object containing the name portion of the strong name.

  • A System.Version object that contains the strong name's version. Version is a utility class that greatly simplifies the manipulation and comparison of assembly version numbers. See the .NET Framework SDK documentation for complete descriptions. Here is the code for the StrongName class constructor:

    # C#
    
    public StrongName (
        StrongNamePublicKeyBlob blob,
        string name,
        Version version
    );
    
    # Visual Basic .NET
    
    Public Sub New( _
        ByVal blob As StrongNamePublicKeyBlob, _
        ByVal name As String, _
        ByVal version As Version _
    )

Each of the arguments provided during construction is available through the read-only Name, PublicKey, and Version properties of the StrongName class.

To obtain the strong-name information required to create a StrongName object you can use the Secutil tool (Secutil.exe) to extract the public key, name, and version from a strong-named assembly. There is no simple way to extract this information using the .NET class library. The following command will extract the strong-name information from the assembly HelloWorld.exe and write it to the strongname.txt file in a format that you can easily incorporate into your program:

secutil -array -cmode -strongname HelloWorld.exe > strongname.txt

The contents of strongname.txt will look something like this:

Microsoft (R) .NET Framework SecUtil 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
 
Public Key =
{ 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 
82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 169, 206, 164, 8, 66, 197, 
231, 138, 148, 74, 99, 125, 171, 203, 120, 143, 240, 155, 104, 138, 
4, 123, 15, 55, 85, 255, 183, 20, 111, 10, 217, 58, 127, 15, 236, 86, 
16, 121, 222, 35, 161, 14, 122, 246, 85, 226, 162, 221, 46, 215, 161, 
151, 183, 38, 31, 150, 198, 119, 109, 94, 11, 65, 208, 33, 122, 172, 
106, 62, 192, 4, 35, 255, 220, 10, 43, 90, 92, 183, 29, 136, 57, 235, 
30, 5, 127, 72, 210, 108, 215, 226, 65, 197, 184, 28, 129, 184, 191, 
211, 159, 69, 8, 84, 116, 65, 186, 179, 35, 116, 174, 223, 167, 217, 
116, 8, 178, 232, 213, 155, 172, 87, 181, 187, 61, 43, 133, 105, 10, 
187 }
Name =
HelloWorld
Version =
1.1578.0.0
Success

With the strong-name information extracted by Secutil, it is a simple matter to create StrongName evidence, as shown below:

# C#

using System;
using System.Security.Policy;
using System.Security.Permissions;

public class StrongNameEvidenceDemo {

    // Create a byte array containing the strong name public key 
    // data.
    static byte[] publickey = { 0, 36, 0, 0, 4, 128, 0, 0, 148, 
    0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 
    0, 1, 0, 1, 0, 169, 206, 164, 8, 66, 197, 231, 138, 148, 74,
    99, 125, 171, 203, 120, 143, 240, 155, 104, 138, 4, 123, 15, 
    55, 85, 255, 183, 20, 111, 10, 217, 58, 127, 15, 236, 86, 16, 
    121, 222, 35, 161, 14, 122, 246, 85, 226, 162, 221, 46, 215, 
    161, 151, 183, 38, 31, 150, 198, 119, 109, 94, 11, 65, 208, 
    33, 122, 172, 106, 62, 192, 4, 35, 255, 220, 10, 43, 90, 92, 
    183, 29, 136, 57, 235, 30, 5, 127, 72, 210, 108, 215, 226, 65, 
    197, 184, 28, 129, 184, 191, 211, 159, 69, 8, 84, 116, 65, 186, 
    179, 35, 116, 174, 223, 167, 217, 116, 8, 178, 232, 213, 155, 
    172, 87, 181, 187, 61, 43, 133, 105, 10, 187 };

    public static void Main(  ) {
    
        // Create a StrongNamePublicKeyBlob object from the 
        // publickey byte array.
        StrongNamePublicKeyBlob blob = 
            new StrongNamePublicKeyBlob(publickey); 
            
        // Create a Version object based on the assembly version 
        // number
        Version version = new Version("1.1578.0.0");
            
        // Create the new StrongName evidence object
        StrongName sn = new StrongName(blob, "HelloWorld", version);
    }
}
    
# Visual Basic .NET

Imports System
Imports System.Security.Policy
Imports System.Security.Permissions
 
Public Class StrongNameEvidenceDemo
 
    ' Create a byte array containing the strong name public key 
    ' data.
    Shared publickey(  ) As Byte = { 0, 36, 0, 0, 4, 128, 0, 0, 148, _
    0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, _
    0, 1, 0, 1, 0, 169, 206, 164, 8, 66, 197, 231, 138, 148, 74, _
    99, 125, 171, 203, 120, 143, 240, 155, 104, 138, 4, 123, 15, _
    55, 85, 255, 183, 20, 111, 10, 217, 58, 127, 15, 236, 86, 16, _
    121, 222, 35, 161, 14, 122, 246, 85, 226, 162, 221, 46, 215, _
    161, 151, 183, 38, 31, 150, 198, 119, 109, 94, 11, 65, 208, _
    33, 122, 172, 106, 62, 192, 4, 35, 255, 220, 10, 43, 90, 92, _
    183, 29, 136, 57, 235, 30, 5, 127, 72, 210, 108, 215, 226, 65, _ 
    197, 184, 28, 129, 184, 191, 211, 159, 69, 8, 84, 116, 65, 186, _
    179, 35, 116, 174, 223, 167, 217, 116, 8, 178, 232, 213, 155, _
    172, 87, 181, 187, 61, 43, 133, 105, 10, 187}
 
    Public Shared  Sub Main(  )
 
        ' Create a StrongNamePublicKeyBlob object from the 
        ' publickey byte array.
        Dim blob As StrongNamePublicKeyBlob = _
            New StrongNamePublicKeyBlob(publickey) 
 
        ' Create a Version object based on the assembly version 
        ' number
        Dim version As Version = New Version("1.1578.0.0") 
 
        ' Create the new StrongName evidence object
        Dim sn As StrongName = New StrongName(blob,"HelloWorld",version) 
                        
    End Sub


End Class
6.2.3.6 The Url class

The System.Security.Policy.Url class provides evidence based on the URL from where an assembly was loaded. If the assembly is loaded using a file path on the local machine, the Url evidence contains a file:// protocol URL; other possibilities are http:// and https:// if the assembly was loaded from a web site.

Because the Url class implements the IIdentityPermissionFactory interface, its presence in the host evidence collection of an assembly causes a System.Security.Permisssions.UrlIdentityPermission to be included in the assembly's grant set. Refer to Chapter 7 for an explanation of identity permissions.

The Url class constructor shown takes a System.String argument specifying the URL from where the assembly was loaded:

# C#

public Url(String name);

# Visual Basic .NET

Public Sub New(ByVal name As String)

The Url constructor performs some validation on the URL string to ensure that file://-based URLs are correctly formatted but does not limit the scope of the protocol you can use.

The read-only Value property returns the URL string used in construction.

6.2.3.7 The Zone class

The System.Security.Policy.Zone class provides evidence based on the Internet Explorer security zone from where an assembly was loaded. The runtime maps the URL of an assembly against the Internet Explorer zone configuration to determine the type of Zone evidence to create.

Because the Zone class implements the IIdentityPermissionFactory interface, its presence in the host evidence collection of an assembly causes a System.Security.Permisssions.ZoneIdentityPermission to be included in the assembly's grant set. Refer to Chapter 7 for an explanation of identity permissions.

The Zone class constructor shown below takes as an argument a member of the System.Security.SecurityZone enumeration which specifies the type of Zone evidence to create; we list the possible values in Table 6-3. The read-only SecurityZone property returns the SecurityZone member specified during construction:

# C#

public Zone (SecurityZone zone);

# Visual Basic .NET

Public Sub New(ByVal zone As SecurityZone)

Table 6-3. Members of the SecurityZone enumeration

Member

Description

Internet

All web sites that do not belong to one of the other zones

Intranet

Web sites located on the local intranet

MyComputer

The local computer

NoZone

No zone specified

Trusted

Specific web sites configured in Internet Explorer to be trusted

UnTrusted

Specific web sites configured in Internet Explorer to be untrusted

The Zone class also provides the static CreateFromUrl factory method to simplify the creation of Zone objects from URL strings. When you call CreateFromUrl the runtime maps the specified URL against the Internet Explorer zone configuration and returns the appropriate Zone object.

The following code demonstrates how to create Zone evidence representing the Trusted zone, as well as how to create a zone from the URL https://www.somecompany.com:8080/dev/HelloWorld.exe:

# C#

String url = "https://www.somecompany.com:8080/dev/HelloWorld.exe";
Zone z1 = Zone.CreateFromUrl(url);        
Zone z2 = new Zone(SecurityZone.Trusted);

# Visual Basic.NET

Dim url As String = "https://www.somecompany.com:8080/dev/HelloWorld.exe" 
Dim z1 As Zone = Zone.CreateFromUrl(url)  
Dim z2 As Zone = New Zone(SecurityZone.Trusted)

6.2.4 Viewing Evidence

The ability to view an assembly's evidence is extremely useful when debugging CAS-related programming issues and will help you to understand the concepts discussed previously. The System.Reflection.Assembly and System.AppDomain classes have read-only Evidence properties that contain the evidence CAS used during policy resolution to determine the assembly's or application domain's permissions. The Evidence property is read-only because, as we described earlier, you can only assign evidence when you load an assembly or create an application domain.

If you try to add new evidence objects to the Evidence collection of an existing Assembly or AppDomain object, no error will occur, but the evidence collection will not be modified.

It is unlikely that you will need to use an evidence in order to make security decisions at runtime. Most of the standard evidence classes result in the inclusion of an appropriate identity permission in the grant set of the assembly. Identity permissions, which we discuss in Chapter 7, are tightly integrated with the CAS framework and allow you to base security decisions on the identity of an assembly.

Example 6-1 shows how to display an assembly's evidence, using a class named LoadAndList, which you should build into an executable named LoadAndList.exe. The LoadAndList class takes the name of an assembly as a command-line argument, loads the specified assembly, and lists the assembly's host and assembly evidence to the console. The LoadAndList class uses the Assembly.Evidence property to get the assembly's evidence and uses two loops to enumerate first the host and then the assembly evidence:

Example 6-1. Displaying an assembly's evidence
# C#

using System;
using System.Reflection;
using System.Collections;
using System.Security.Policy;

public class LoadAndList {

    public static void Main(string[] args) {
           
        // Load the specified assembly   
        Assembly a = Assembly.LoadFrom(args[0]);
            
        // Get the Evidence collection from the 
        // loaded assembly        
        Evidence e = a.Evidence;
                                
        // Display the Host Evidence
        IEnumerator x = e.GetHostEnumerator(  );
        Console.WriteLine("HOST EVIDENCE:");
        while(x.MoveNext(  )) {
            Console.WriteLine(x.Current.ToString(  ));
        }

        // Display the Assembly Evidence
        x = e.GetAssemblyEnumerator(  );
        Console.WriteLine("ASSEMBLY EVIDENCE:");
        while(x.MoveNext(  )) {
            Console.WriteLine(x.Current.ToString(  ));
        }
    }
}

# Visual Basic .NET

Imports System
Imports System.Collections
Imports System.Security.Policy
 
Public Class LoadAndList
 
    Public Shared  Sub Main(ByVal args(  ) As String)
 
        ' Load the specified assembly   
        Dim a As System.Reflection.Assembly = _
            System.Reflection.Assembly.LoadFrom(args(0)) 
 
        ' Get the Evidence collection from the 
        ' loaded assembly        
        Dim e As Evidence = a.Evidence 
 
        ' Display the Host Evidence
        Dim x As IEnumerator = e.GetHostEnumerator(  ) 
        Console.WriteLine("HOST EVIDENCE:")
        While x.MoveNext(  )
            Console.WriteLine(x.Current.ToString(  ))
        End While
 
        ' Display the Assembly Evidence
        x = e.GetAssemblyEnumerator(  )
        Console.WriteLine("ASSEMBLY EVIDENCE:")
        While x.MoveNext(  )
            Console.WriteLine(x.Current.ToString(  ))
        End While
    End Sub
End Class

The LoadAndList utility provides you with the opportunity to demonstrate an important point we made earlier in this chapter: the identity of an assembly can vary greatly based on the location from which it is loaded, resulting in the assembly being granted a different set of permissions.

Instead of the path of an assembly file, pass LoadAndList the URL of an assembly to load. If you place an assembly in the root directory of a Microsoft Internet Information Services (IIS) server running on your local machine, the evidence assigned to the assembly will be very different if you access it using an HTTP URL as opposed to the a file path.

For example, if you take any assembly (use one named HelloWorld.exe) and place it in the root directory of the IIS server running on our Windows 2000 machine, executing the command LoadAndList C:\Inetpub\wwwroot\HelloWorld.exe results in the following display of host evidence (the Hash evidence is abbreviated):

HOST EVIDENCE:
<System.Security.Policy.Zone version="1">
   <Zone>MyComputer</Zone>
</System.Security.Policy.Zone>

<System.Security.Policy.Url version="1">
   <Url>file://C:/Inetpub/wwwroot/HelloWorld.exe</Url>
</System.Security.Policy.Url>

<System.Security.Policy.Hash version="1">
   <RawData>4D5A90000300000004000000FFFF000</RawData>
</System.Security.Policy.Hash>

Alternatively, executing the command LoadAndList http://localhost/HelloWorld.exe results in a very different set of host evidence despite the fact that you are looking at the same assembly. Notice the changes (highlighted below) to the value of the Zone and Url evidence, and the addition of the new Site evidence. The Hash evidence (based on the content of the assembly) remains unchanged, as would StrongName and Publisher evidence if it were present. Notice that in both cases, the assembly evidence collection is empty:

HOST EVIDENCE:
<System.Security.Policy.Zone version="1">
   <Zone>Intranet</Zone>
</System.Security.Policy.Zone>

<System.Security.Policy.Url version="1">
   <Url>http://localhost/HelloWorld.exe</Url>
</System.Security.Policy.Url>

<System.Security.Policy.Site version="1">
   <Name>localhost</Name>
</System.Security.Policy.Site>

<System.Security.Policy.Hash version="1">
   <RawData>4D5A90000300000004000000FFFF000</RawData>
</System.Security.Policy.Hash>

6.2.5 Assigning Evidence to Assemblies

Table 6-4 lists the most commonly used methods of the AppDomain and Assembly classes that directly or indirectly result in the runtime loading an assembly. Each of these methods has one or more overloads that allow you to provide an Evidence collection for the loaded assembly.

Table 6-4. AppDomain and Assembly methods that take Evidence collections

Method

Description

System.AppDomain

 

CreateInstance

Instantiate a class contained in the specified assembly

CreateInstanceAndUnwrap

 

CreateInstanceFrom

 

CreateInstanceFromAndUnwrap

 

DefineDynamicAssembly

Defines a dynamic assembly

ExecuteAssembly

Loads and executes the specified assembly

Load

Loads the specified assembly into the application domain

System.Reflection.Assembly

 

Load

Load the specified assembly into the current application domain

LoadFrom

 

LoadWithPartialName

 

Although the purpose and signatures of the methods listed in Table 6-4 vary, the steps necessary to supply evidence to a new assembly are the same:

  1. Create an Evidence collection object.

  2. Instantiate the individual evidence objects and add them to the Evidence collection using the AddHost method.

  3. Execute the method to load the assembly, passing it the Evidence collection as an argument.

Example 6-2 shows how to assign evidence to an assembly, using a modified version of the LoadAndList class (from Example 6-1) named LoadAndAssign. The LoadAndAssign class loads a named assembly, and assigns it new Site, Url, and Zone host evidence. Because we do not discuss the use of permission requests until Chapter 7, we catch all exceptions and display a message to the user. If you execute LoadAndAssign from your local machine, there should be no problem with permissions as long as you have not modified the default security policy. However, you should always handle any security exceptions that you know might be thrown.

Example 6-2. Assigning evidence to an assembly
# C#

using System;
using System.Reflection;
using System.Collections;
using System.Security;
using System.Security.Policy;

public class LoadAndAssign {

    public static void Main(string[] args) {
                    
        // Create a new Evidence collection 
        Evidence e = new Evidence(  );

        // Add host evidence to the Evidence collection
        e.AddHost(new Site("www.oreilly.com"));
        e.AddHost(new Url(@"file://C:/Dev/Test.exe"));   
        e.AddHost(new Zone(SecurityZone.Trusted));

        // Create a new Assembly reference
        Assembly a = null;

        try {
        
            // Load the specified assembly and provide the Evidence
            // collection
            a = Assembly.LoadFrom(args[0], e);

        } catch (Exception ex) {

            Console.WriteLine("Could not load assembly - {0}.", args[0]);
            Console.WriteLine(ex);
            return;
        }
            
        // Display the Host Evidence of the assembly
        IEnumerator x = a.Evidence.GetHostEnumerator(  );
        Console.WriteLine("HOST EVIDENCE:");
        while(x.MoveNext(  )) {
            Console.WriteLine(x.Current.ToString(  ));
        }

        // Display the Assembly Evidence of the assembly
        x = a.Evidence.GetAssemblyEnumerator(  );
        Console.WriteLine("ASSEMBLY EVIDENCE:");
        while(x.MoveNext(  )) {
            Console.WriteLine(x.Current.ToString(  ));
        }
    }
}

# Visual Basic .NET

Imports System 
Imports System.Collections 
Imports System.Security 
Imports System.Security.Policy 

Public Class LoadAndAssign

    Public Shared  Sub Main(ByVal args(  ) As String)
                    
        ' Create a new Evidence collection 
        Dim e As Evidence = new Evidence(  ) 

        ' Add host evidence to the Evidence collection
        e.AddHost(new Site("www.oreilly.com")) 
        e.AddHost(new Url("file://C:/Dev/Test.exe"))    
        e.AddHost(new Zone(SecurityZone.Trusted)) 

        ' Create a new Assembly reference
        Dim a As System.Reflection.Assembly = Nothing
        
        Try        
            ' Load the specified assembly and provide the Evidence
            ' collection
            a = System.Reflection.Assembly.LoadFrom(args(0), e) 
        Catch ex As SecurityException
            Console.WriteLine("Could not load assembly - {0}.", args(0))
            Console.WriteLine(ex)
            Return
        End Try

        ' Display the Host Evidence of the assembly
        Dim x As IEnumerator = a.Evidence.GetHostEnumerator(  ) 
        Console.WriteLine("HOST EVIDENCE:") 
        While x.MoveNext(  )
            Console.WriteLine(x.Current.ToString(  ))
        End While

        ' Display the Assembly Evidence of the assembly
        x = a.Evidence.GetAssemblyEnumerator(  ) 
        Console.WriteLine("ASSEMBLY EVIDENCE:") 
        While x.MoveNext(  )
            Console.WriteLine(x.Current.ToString(  ))
        End While
    End Sub
End Class

From the command line, entering the command LoadAndAssign C:\Inetpub\wwwroot\HelloWorld.exe to load the HelloWorld.exe assembly you used in Example 6-1 results in the display of host evidence similar to that listed below. The Url and Zone evidence you specified has replaced the default evidence. There is also Site evidence, which was previously present only when you used an HTTP URL to specify the location of the assembly:

HOST EVIDENCE:
<System.Security.Policy.Hash version="1">
   <RawData>4D5A90000300000004000000FFFF000</RawData>
</System.Security.Policy.Hash>

<System.Security.Policy.Site version="1">
   <Name>www.oreilly.com</Name>
</System.Security.Policy.Site>

<System.Security.Policy.Url version="1">
   <Url>file://C:/Dev/Test.exe</Url>
</System.Security.Policy.Url>

<System.Security.Policy.Zone version="1">
   <Zone>Trusted</Zone>
</System.Security.Policy.Zone>

6.2.6 Assigning Evidence to Application Domains

Many of the standard evidence types are more applicable to assemblies than to application domains, but there is nothing to stop you assigning any of the evidence types of application domains.

For example, although it is impossible to sign an application domain with a publisher certificate, you could still assign Publisher evidence to an application domain manually. This may be appropriate on a server that runs code on behalf of many different companies. You may decide to run all code from a single company in its own application domain. Assigning the application domain Publisher evidence ensures that any code running within the application domain is limited to the permissions you assign to that particular company. The benefits of application domain evidence will become clearer when we discuss security demands and stack walks in Chapter 7.

When you create an application domain using the static AppDomain.CreateDomain method, two of the method overloads give you the option of providing an Evidence collection for the new application domain:

# C#

public static AppDomain CreateDomain(
    string friendlyName,
    Evidence securityInfo,
    AppDomainSetup info
);

public static AppDomain CreateDomain(
    string friendlyName,
    Evidence securityInfo,
    string appBasePath,
    string appRelativeSearchPath,
    bool shadowCopyFiles
);

# Visual Basic .NET

Overloads Public Shared Function CreateDomain( _
    ByVal friendlyName As String, _
    ByVal securityInfo As Evidence, _
    ByVal info As AppDomainSetup _
) As AppDomain

Overloads Public Shared Function CreateDomain( _
    ByVal friendlyName As String, _
    ByVal securityInfo As Evidence, _
    ByVal appBasePath As String, _
    ByVal appRelativeSearchPath As String, _
    ByVal shadowCopyFiles As Boolean _
) As AppDomain

The process of specifying evidence for an application domain is the same as for assemblies except that you pass the Evidence collection populated with evidence objects to the CreateDomain method:

# C#

// Create an empty Evidence collection
Evidence e = New Evidence(  );

// Add Host and Assembly Evidence
e.AddHost(new Site("www.oreilly.com"));
e.AddHost(new Zone(SecurityZone.Trusted));

// Create a new application domain reference.
AppDomain d = null;

try {
        
    // Create the new application domain
    d = AppDomain.CreateDomain("New Domain", e, null);

} catch (Exception ex) {

    Console.WriteLine("Could not create application domain");
    Console.WriteLine(ex);
}

# Visual Basic .NET

' Create an empty Evidence collection
Dim e As Evidence = New Evidence(  ) 
 
' Add Host and Assembly Evidence
e.AddHost(New Site("www.oreilly.com"))
e.AddHost(New Zone(SecurityZone.Trusted))

' Create a new application domain reference.
Dim d As AppDomain = Nothing

Try
        
    ' Create the new application domain
    d = AppDomain.CreateDomain("New Domain",e,Nothing)

Catch ex As Exception

    Console.WriteLine("Could not create application domain")
    Console.WriteLine(ex)
End Try

Be aware of the following behavior:

  • The runtime host determines the evidence assigned to the initial application domain. In the case of the shell runtime host, the default application domain is assigned the same set of evidence assigned to the assembly whose execution caused the CLR to be loaded.

  • If you specify null (C#) or Nothing (Visual Basic .NET) as the Evidence argument to the CreateDomain method, the runtime assigns the new application domain the same evidence that is assigned to the current application domain.

  • If you pass an empty Evidence collection to the CreateDomain method, the application domain will have no evidence. This does not mean that code running in the application domain has no permissions; in fact, it means the application domain is transparent to security permission checks (which means that the application domain has no effect on the permissions of the code running in it). See Chapter 7 for details.

    [ Team LiB ] Previous Section Next Section