SECURITY

Evidence and Code Identity: Extending the .NET Framework

9/14/2010 6:05:51 PM

The standard .NET evidence classes represent the most commonly available and useful characteristics of an assembly. For most situations, these classes provide enough reliable information from which to determine a unique identity for an assembly, enabling you to configure your security policy. However, there are times when the systems you develop need to provide users, administrators, and programmers with additional criteria on which to base their security policy decisions. CAS supports the use of custom evidence to meet this requirement.

The creation of custom evidence is a simple task, but there are more steps before you can drive the policy resolution process using your custom evidence. In the following sections, we discuss the creation of a custom evidence class.

1. Creating Custom Evidence

You can use any serializable class as evidence. There are no evidence-specific interfaces to implement, nor do you need to derive from a common base class (other than System.Object). However, here are some guidelines to consider when implementing custom evidence classes:

  • Make evidence simple. Evidence classes tend to be relatively simple classes that represent a single piece or type of information. Creating evidence classes that represent multiple or complex sets of data will result in security policy that is difficult for security administrators and users to configure and understand. If you need to represent multiple pieces of information, then create separate evidence classes for each.

  • Make evidence lightweight. When the runtime loads an assembly, it must instantiate the objects that represent the assembly's evidence. These objects stay in memory until the assembly is unloaded or the runtime terminates. Consider the amount of memory used by your evidence classes as well as avoid lengthy processing tasks, such as network, file, and database access during instantiation.

  • Make evidence serializable. Evidence classes must be serializable. Because of their simplicity, application of the System.SerializableAttribute is usually sufficient. Those evidence classes that have more complex serialization requirements must implement the System.Runtime.Serialization.ISerializable interface.

Unless you implement ISerializable, deserialization of an object does not result in the execution of a constructor, and you should not depend on constructor logic to configure or modify the state of the de-serialized object.


  • Make evidence noninheritable. It is safest to mark your evidence classes as sealed in C# and NotInheritable in Visual Basic .NET so that malicious code cannot subclass your evidence class in an attempt to change its behavior and subvert CAS.

  • Don't assume default values. You should consider whether it is appropriate for your evidence class to assume default evidence values if the caller does not explicitly set them during creation. The approach taken by the standard evidence classes is never to provide default values for evidence. None of the standard evidence classes implements a default (empty) constructor, nor do they make assumptions about the value of incorrectly specified arguments. In all cases, the evidence classes' constructor throws a System.ArgumentNullException if passed null arguments. If arguments have invalid values, the constructor throws a System.ArgumentException.

  • Make evidence immutable. Once created, the information held within an evidence class should be immutable. The evidence assigned to an assembly or application domain is accessible to many classes during policy resolution. It would cause problems if these classes could change the values of the evidence part way through the policy resolution process.

  • Override Object.ToString. All standard evidence classes override the Object.ToString method to display a simple XML representation of the evidence object. For consistency, you should consider taking the same approach. Being able to display the contents of evidence is invaluable when testing and debugging.

  • Grant identity permissions. To create evidence that will result in the granting of custom identity permissions, your evidence class must implement the System.Security.Policy.IIdentityPermissionFactory interface.

1.1. Defining the Author evidence class

To demonstrate the creation and use of custom evidence, create the Author class shown in Example 1. The Author class provides evidence containing the name of the programmer who developed an assembly. Our ultimate goal is to assign code-access permissions to assemblies based on the assembly's Author evidence and to make runtime security decisions based on the assembly's Author using identity permissions.

In reality, you would be foolish to place any trust in evidence such as the Author class because it is susceptible to easy falsification. There is nothing to stop someone from assigning Author evidence that represents someone else to an assembly. However, Author is more than adequate for the purpose of our customization demonstration:

Example 1. Creating a custom evidence class
# C#

using System;
using System.Security;
using System.Reflection;

[assembly:AssemblyKeyFile("Keys.snk")]
[assembly:AssemblyVersion("1.0.0.0")]

namespace ORA.DotNetSecurity.Policy {

[Serializable]
public sealed class Author {

private readonly string AuthorName = "";

public Author (string author) {

if (author == null) {
throw new ArgumentNullException("author");
} else {
this.AuthorName = author;
}
}

public string Name {

get {
return AuthorName;
}
}

// Return string representation of the Author object
public override string ToString( ) {

// Create a new "Author" element
SecurityElement se =
new SecurityElement(this.GetType( ).FullName);

// Add version of "1"
se.AddAttribute("version", "1");

// Add a child element to contain the author name
if(AuthorName != "") {
se.AddChild(new SecurityElement("Author", AuthorName));
}

// Render the SecurityElement to a string and return it
return se.ToString( );
}
}
}

# Visual Basic .NET

Imports System
Imports System.Security
Imports System.Reflection




Namespace ORA.DotNetSecurity.Policy

_
Public NotInheritable Class Author

Private AuthorName As String = ""

Public Sub New(ByVal author As String)
If author Is Nothing Then
Throw New ArgumentNullException("author")
Else
Me.AuthorName = author
End If
End Sub

Public ReadOnly Property Name( ) As String
Get
Return AuthorName
End Get
End Property

' Return string representation of the Author object
Public Overrides Function ToString( ) As String

' Create a new "Author" element
Dim se As SecurityElement = _
New SecurityElement(Me.GetType( ).FullName)

' Add version of "1"
se.AddAttribute("version", "1")

' Add a child element to contain the author name
If AuthorName <> "" Then
se.AddChild(New SecurityElement("Author",AuthorName))
End If

' Render the SecurityElement to a string and return it
Return se.ToString( )
End Function
End Class
End Namespace


The Author class implements many of the guidelines we outlined earlier, such as:

  • Author is sealed (C#) and NotInheritable (Visual Basic .NET), ensuring that nobody can create a subclass that behaves differently than we intended.

  • Author contains a single data member: a String named AuthorName, which contains the name of the author represented by the evidence object. AuthorName is a read-only private member that can be set only on instantiation and is retrievable only through the Name property, ensuring that Author is immutable.

  • Author is made serializable using SerializableAttribute. Because Author contains only a single String member, the default serialization capabilities provided by the SerializableAttribute are sufficient.

  • Author overrides the Object.ToString method to render an Author object to XML in a format consistent with the standard evidence types. Author builds the XML representation using the System.Security.SecurityElement class, which we discuss in the next section, before returning it as a String. The output of ToString for an Author object representing the author "Peter" is shown below. The version attribute identifies the format of XML output in case you decide to represent future versions of the Author class differently.


    Peter

1.2. Using the SecurityElement Class

System.Security.SecurityElement is a utility class that implements a simple, lightweight XML object model for encoding .NET security objects. SecurityElement lacks the functionality required for general-purpose XML processing but is sufficient for use within the security system where only simple XML representations are required. When extending the .NET security system, you will frequently need to use SecurityElement, which is why understanding how it works is essential.

A SecurityElement object represents a single XML element and provides members that allow you to specify the following characteristics:

  • The element name or tag

  • Attributes of the element

  • Child elements (also represented by SecurityElement objects)

  • Text within the body of the element

SecurityElement also includes methods that allow you to perform simple searches of your XML element and its children, as well as static utility methods for manipulating and testing the validity of string values used within SecurityElement objects. The Author.ToString method demonstrates the use of SecurityElement, where we develop further CAS extensions. Table 1 lists the members of SecurityElement.

SecurityElement provides flexibility in how you model the XML representation of your data. The .NET SDK documentation recommends that in the interest of readability and portability, you use attributes instead of child elements wherever possible and avoid text nested within tags. You will notice however, that all of the standard evidence classes use nested text values.


Table 1. Members of the SecurityElement class
Member Description
Properties  
Attributes Gets and sets the attributes of a SecurityElement using a System.Collections.Hashtable containing a collection of name/value string pairs representing the attributes.
Children Gets and sets the child elements by providing a System.Collections.ArrayList of SecurityElements.
Tag Gets or sets the tag of the SecurityElement.
Text Gets or sets the text of the SecurityElement.
Methods  
AddAttribute Adds an attribute with the specified name and value to the SecurityElement.
AddChild Adds the specified SecurityElement as a child element.
Methods  
Attribute Finds an attribute by name and returns its value, returning null (C#) or Nothing (Visual Basic .NET) if the attribute does not exist.
Equal Tests two SecurityElement objects for equality by comparing tags, attributes, text, and child elements. This is different than the inherited Object.Equals method.
Escape Static utility method for encoding invalid characters (that are invalid within XML) as valid escape sequences. Use the resulting string as a tag, attribute, or text value within the SecurityElement.
IsValidAttributeName Static utility method that tests if a string represents a valid attribute name.
IsValidAttributeValue Static utility method that tests if a string represents a valid attribute value.
IsValidTag Static utility method that tests if a string represents a valid element tag.
IsValidText Static utility method that tests if a string represents valid element text.
SearchForChildByTag Searches the SecurityElement for the first child with the specified tag, returning the child as a SecurityElement. This method does not perform a recursive search; it searches only the immediate child elements.
SearchForTextOfTag Searches the SecurityElement for the first child with the specified tag and returns the child's text. This method searches recursively through all child elements.
ToString Returns a System.String containing the XML representation of the SecurityElement and its children.

1.3. Building the Author evidence class

For reasons that we will explain shortly, Author.dll needs a strong name, so we have included the AssemblyKeyFile and AssemblyVersion attributes. . For this example, the AssemblyKeyFile attribute references a key file named Keys.snk, which we generated solely for this demonstration using the .NET Strong Name tool (Sn.exe). You should create the Keys.snk file and compile the Author class into a library named Author.dll using the following commands:

# C# 

sn -k Keys.snk
csc /target:library Author.cs

# Visual Basic .NET

sn -k Keys.snk
vbc /target:library Author.vb

2. Using Custom Evidence

The previous section explains that the runtime recognizes two categories of evidence: host evidence and assembly evidence. Using custom evidence as host evidence at runtime is no different from using standard evidence; refer to Evidence Explained for details.

Because you must embed assembly evidence in the target assembly file, the use of custom evidence as assembly evidence involves additional steps during the build process of the assembly. You must prepare the custom assembly evidence programmatically, which you would normally do with a separate utility program, as we demonstrate later in this section. The process, illustrated in Figure 1, is as follows:

  1. Create a System.Security.Policy.Evidence collection.

  2. Create the objects you want to assign as assembly evidence.

  3. Add the evidence objects to the Evidence collection using the AddAssembly method.

    There is no benefit in using the AddHost method to add evidence, because the runtime simply ignores host evidence when loading an assembly.

  4. Serialize the Evidence collection using an instance of the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter class and write it to a file.

  5. Build your code into a set of modules using the /target:module flag on the C# or Visual Basic .NET compiler.

  6. Combine the modules and the evidence resource into an assembly using the Assembly Linker tool (al.exe). Use the /evidence:file flag to specify the file containing the serialized assembly evidence.

Figure 1. Embedding custom evidence in an assembly

In the following sections, we expand on this summary and demonstrate exactly how to use Author evidence as embedded assembly evidence, but first we must make Assembly.dll a fully trusted assembly.

6.3.2.1. Making the Author assembly a fully trusted assembly

Assemblies that provide CAS extensions (such as the Author.dll in the previous section) must be fully trusted by the security system. This avoids problems when the runtime loads the assembly during the policy resolution process. We discuss the need for fully trusted assemblies , type the following commands:

gacutil -i Author.dll
caspol -user -addfulltrust Author.dll
caspol -machine -addfulltrust Author.dll
caspol -enterprise -addfulltrust Author.dll

The first command installs Author.dll into the global assembly cache; which you must do before you can make it a fully trusted assembly. This is why you had to give Author.dll a strong name when you built it. The other commands make Author.dll a fully trusted assembly in the user, machine, and enterprise policy levels.

2.2. Serializing evidence

To embed evidence in an assembly, you must serialize an Evidence collection that contains the evidence objects you want to use as assembly evidence. The .NET class library includes the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter class, which makes the serialization of serializable objects a straightforward process.

Example 2 contains a simple utility named CreateAuthorEvidenceResource that creates an Author object using a name provided on the command line, adds the Author object to an Evidence collection, and then serializes the Evidence collection to a file. Running the command CreateAuthorEvidenceResource Peter results in the creation of the file named Peter.evidence that contains the serialized Evidence collection; you can then embed that file into the assembly.

Example 2. The CreateAuthorEvidenceResource utility
# C#

using System;
using System.IO;
using System.Security.Policy;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using ORA.DotNetSecurity.Policy;

public class CreateAuthorEvidenceResource {

public static void Main(string[] args) {

// Create a new Evidence collection
Evidence ev = new Evidence( );

// Create and configure new Author object
Author auth = new Author(args[0]);

// Add the new Author object to the assembly evidence
// collection of the Evidence object
ev.AddAssembly(auth);

// Generate the name of the output file
String file = auth.Name + ".evidence";

// Serialize the Evidence object
IFormatter fmtr = new BinaryFormatter( );
Stream strm = new FileStream(file,
FileMode.Create,
FileAccess.Write,
FileShare.None);
fmtr.Serialize(strm, ev);
strm.Close( );

// Display result
Console.WriteLine("Created author evidence resource : " +
file);
}
}

# Visual Basic .NET

Imports System
Imports System.IO
Imports System.Security.Policy
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary
Imports ORA.DotNetSecurity.Policy

Public Class CreateAuthorEvidenceResource

Public Shared Sub Main(ByVal args( ) As String)

' Create a new Evidence collection
Dim ev As Evidence = New Evidence( )

' Create and configure new Author object
Dim auth As Author = New Author(args(0))

' Add the new Author object to the assembly evidence
' collection of the Evidence object
ev.AddAssembly(auth)

' Generate the name of the output file
Dim file As String = auth.Name & ".evidence"

' Serialize the Evidence object
Dim fmtr As IFormatter = New BinaryFormatter( )
Dim strm As Stream = New FileStream(file, _
FileMode.Create, _
FileAccess.Write, _
FileShare.None)
fmtr.Serialize(strm, ev)
strm.Close( )

' Display result
Console.WriteLine("Created author evidence resource : " & _
file)
End Sub
End Class


If you use custom evidence classes, or provide them to third parties to use in their own application development, provision of a utility similar to CreateAuthorEvidenceResource makes everyone's life a lot easier.

Build the CreateAuthorEvidenceResource class into an executable using the following command; remember, there is a dependency on the Author.dll assembly:

# C#

csc /reference:Author.dll CreateAuthorEvidenceResource.cs

# Visual Basic .NET

vbc /reference:Author.dll CreateAuthorEvidenceResource.vb

2.3. Embedding evidence in an assembly

We now have a mechanism for creating serialized Evidence collections, but we need a target assembly in which to embed the evidence. The simple HelloWorld class listed here will do for the purpose of this example:

# C#

using System;

public class HelloWorld {
public static void Main( ) {
Console.WriteLine("HelloWorld");
}
}

# Visual Basic .NET

Imports System

Public Class HelloWorld
Public Shared Sub Main( )
Console.WriteLine("HelloWorld")
End Sub
End Class

Embedding serialized evidence into your target assembly requires the use of the Assembly Linker tool (al.exe), which comes with the .NET Framework SDK. The Assembly Linker tool takes a number of modules and resources and combines them to create an assembly. You must first build your source into modules using the C# or Visual Basic .NET compilers and then combine the resulting modules, along with your evidence, into an assembly.

Assuming you have already built the Author.dll library and the CreateAuthorEvidenceResource.exe executable (as demonstrated in the previous sections), the following series of commands creates the HelloWorld.exe assembly complete with assembly evidence representing the author Peter:

# C#

CreateAuthorEvidenceResource Peter
csc /target:module HelloWorld.cs

al /target:exe /out:HelloWorld.exe /main:HelloWorld.Main
/evidence:Peter.evidence HelloWorld.netmodule

# Visual Basic .NET

CreateAuthorEvidenceResource Peter
vbc /target:module HelloWorld.vb

al /t:exe /out:HelloWorld.exe /main:HelloWorld.Main
/evidence:Peter.evidence HelloWorld.netmodule

The first command calls our CreateAuthorEvidenceResource utility, which creates a binary security resource file containing an Author evidence object for the author named Peter. Then you compile the HelloWorld source file into a module. Finally, you use the Assembly Linker tool to combine HelloWorld.netmodule and the Peter.evidence security resource to form the executable assembly named HelloWorld.exe.

Now run the LoadAndList utility developed in Example 1 to view the evidence assigned to the HelloWorld.exe assembly when it is loaded. For example, if you place HelloWorld.exe in the directory C:\dev, and run the command LoadAndList C:\Dev\HelloWorld.exe, you see output similar to that shown below (the Hash evidence is abbreviated). Notice the inclusion of the Author evidence in the assembly evidence collection:
HOST EVIDENCE:

MyComputer



file://C:/Dev/HelloWorld.exe



4D5A90000300000004000000FFFF0000B80000000000000040


ASSEMBLY EVIDENCE:

Peter

If you were to modify the CreateAuthorEvidenceResource class to write the Author evidence into the host subcollection of the Evidence class (using the AddHostAddAssembly method), not only would the assembly evidence collection be empty, but the Author evidence would not be present in the host evidence of HelloWorld.exe because the runtime would ignore it. method instead of the

3. The Next Steps in Customization

Now you have the Author evidence class that represents the programmer who developed an assembly. You can assign Author evidence as host evidence at runtime and embed it as assembly evidence during the build process. Unfortunately, you are not yet able to grant code-access permission based on the Author of an assembly.

Other  
 
Top 10
Review : Sigma 24mm f/1.4 DG HSM Art
Review : Canon EF11-24mm f/4L USM
Review : Creative Sound Blaster Roar 2
Review : Philips Fidelio M2L
Review : Alienware 17 - Dell's Alienware laptops
Review Smartwatch : Wellograph
Review : Xiaomi Redmi 2
Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
REVIEW
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
VIDEO TUTORIAL
- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
Popular Tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8