Code Access Security
The .NET Framework is based on the concept of distributed applications, in which an application does not necessarily have a single owner. To circumvent the problem of which parts of the application (being assemblies) to trust, code access security is introduced. This is a very powerful way to protect the system from code that may be malicious or just unstable. Remember that it is always active, even if you do not use it in your own code. CAS helps you with the following tasks:
Limiting access permissions of assemblies by applying security policies
Protecting the code from obtaining more permissions than the security policy initially permits
Managing and configuring permission sets within security policies to reflect the specific security needs
Granting assemblies specific permissions that they request
Enabling assemblies in demanding specific permissions from the caller
Using the caller’s identity and credentials to access protected resources and code
.NET Code Access Security Model
The .NET Code Access Security (CAS) model is based on a number of features:
Stack walking
Code identity
Code groups
Declarative and imperative security
Requesting permissions
Demanding permissions
Overriding security checks
Custom permissions
The following discussion will give you a better understanding of how CAS works in general and how it can work for you as you design and implement .NET applications.
Stack Walking
Perhaps stack walking is the most important mechanism within CAS to ensure that assemblies cannot gain access to protected resources and code during the course of the execution. As we mentioned before, one of the initial steps in the assembly load process is determining the level of trust of the assembly and associating corresponding permission sets with the assembly. The total package of sets is the maximum number of permissions an assembly can obtain.
Because the code in an assembly can call a method in another assembly and so forth, a calling chain develops (see Figure A.1), with every assembly having its own permissions set. Suppose that an assembly demands that its caller have a specific permission (UIPermission in Figure A.1) to be able to execute the method. Now the stack walking of the CLR kicks in. The CLR starts checking the stack where every assembly in the calling chain has its own data segment. Going back in the stack, every assembly the CLR checks for the presence of this demanded permission—in our case, UIPermission. If all assemblies have this permission, the code can execute. If, however, somewhere in the stack an assembly does not have this permission (in our case, this is in the top assembly Assembly1), the CLR throws an exception and denies access to the method.

Figure A.1: Performing Stack Walking to Prevent Unauthorized Access
Stack walking prevents calling code from gaining access to protected resources and code for which it initially does not have authorization. You can conclude that at any point of the calling chain, the effective permission set is equal to the intersection of the permission sets of the assemblies involved.
Even if you do not incorporate the permission demand in your code, stack walking will take place because all class libraries that come with the CLR use the demand to ensure the secure working of the CLR. The only drawback of stack walking is that it can have a serious performance impact, especially if the calling chain is long. Suppose the stack contains eight assemblies, and the top assembly makes a call to a method that demands a specific permission and does so in a 200-fold loop. The loop triggers 200 security stack walks. Since each stack walk performs eight security checks, the total number of security checks is 1600.
Code Identity
The whole principle of.NET Framework security rides on code identity, or to what level a piece of code can be trusted. The CLR establishes the code identity based on the evidence presented. Evidence comes from two sources:
Evidence that is incorporated in the assembly during the coding and subsequent compiling of the code or that can be added to the assembly later.
Evidence provided by the host where the assembly resides. The CLR controls the accepting of host evidence through the security permission ControlEvidence, which you should only grant to trusted hosts.
Table A.1 lists the default evidence that can be used to determine to what code group particular code belongs. Because you cannot control the identity of the assembly, you are never sure how reliable this evidence is, except for the signatures provided.
Evidence | Description |
|---|---|
Directory | The directory where the application—hence, assembly—is installed. |
Hash | The cryptographic hash of the code: MD5 or SHA1 (see the “Cryptography” section). |
Publisher | The signature of the assembly’s owner, in the form of a X.509 certificate, set through Authenticode. |
Site | The name of the site from which the assembly originates—for example, www.company.com. (Prefixes and suffixes are disregarded.) |
Strong name | The strong name consists of the assembly name (given name), public key (of the publisher), version numbers, and culture. |
URL | The full URL, also called code base, including prefix and suffix: https://www.company.com:4330/*. |
Zone | The zone in which the assembly originates. Default zones are Internet, Local Intranet, My Computer, No Zone Evidence, Trusted Sites, and Untrusted (Restricted) Sites. |
The more evidence you can gather about the assembly, the better you can determine to what extent you can grant it permissions. The strong name is of great importance. If you and all other serious application developers are persistent in providing assemblies with strong names, you can prevent your code from becoming the vehicle of someone’s dubious intents. Sadly enough, malicious code can still have a convincing strong name, which is why the best evidence is the certificate and signature that should be present with the assembly. Once you establish the trustworthiness of an assembly, based on all the evidence before you, you can determine the appropriate permission sets. Here is where your realm of control starts—by constructing appropriate code groups.
Code Groups
A code group is a group of assemblies that share the same value for one, and only one, piece of evidence, called membership condition. Based on this evidence, a permission set is attached to the assembly. Because a code group is part of a code group hierarchy (see Figure A.2), an assembly can be part of more code groups. The effective permission set of the assembly is the union of the permission sets of the code groups to which it belongs.

Figure A.2: Graphical Representation of a Code Group Hierarchy
When an assembly is about to be loaded, the evidence is collected and the code group hierarchy is checked. When the CLR matches an assembly with a code group, it checks the assembly’s child code groups. This implies that the construction of the hierarchy is very important and must start with the general evidence items—for example, starting with zone and moving on to more specific items such as publisher. A complicating factor is that there are three security levels (Enterprise, Machine, and User), each with its own code group hierarchy. The CLR evaluates all three, resulting in three separate permission sets, which it intersects to establish an effective permission set.
It is the administrator’s responsibility to construct code group hierarchies that can quickly be scanned and enforce a high level of security. To do so, you must:
Limit the number of levels.
Use at the first level membership conditions that are discriminatory, preventing checking of large parts of the hierarchy.
The hierarchy’s root, All Code, should have no permissions assigned, so code that does not contain at least some evidence is not allowed to run.
The more convincing the evidence—for example, the publishers certificate—the more permissions can be granted.
Make no exceptions or shortcuts by giving out more permissions than the evidence justifies. Assume that you have a specific application running in the intranet zone that needs to have full trust to operate. Because it is your own application, you implicitly trust it, without the factual evidence. If you do this, however, it can come back to haunt you.
Table A.2 lists the available default membership conditions. You can construct your own, but a discussion of how to do so is beyond the scope of this appendix. We discuss membership conditions in more detail later in the appendix.
Membership Condition | Description |
|---|---|
All Code | Applies to every assembly that is loaded. |
Application directory | Applies to all assemblies that reside in the same directory tree as the running application; hence, the Application domain. |
Hash | Applies to all the assemblies that use the same hash algorithm as specified or have the specified hash value. |
Publisher | Applies to all assemblies that carry the specified publishers certificate. |
Site | Applies to all assemblies that originate from the same site. |
Skip verification | Applies to all assemblies that request the Skip Verification permission. Warning: This permission allows for the bypassing of type safety. Use it only at the lowest level, after you have established that the code is fully trusted. |
Strong name | Applies to all assemblies that have the specified strong name. |
URL | Applies to all assemblies that originate from the specified URL, including prefix, suffix, path, and eventual wildcard. |
Zone | Applies to all assemblies that reside in the specified zone. |
(custom) | Applies to custom-made conditions that are normally directly related to specific applications. |
Declarative and Imperative Security
You can add security to your code in two ways: via a demand that callers have a specific permission or by a request for a specific permission from the CLR.
The first method is declarative security, which can be set at the assembly, class, and/or member level, so you can demand different permissions at different places in the assembly. The VB.NET syntax of declarative code is:
<[assembly:]Permission(SecurityAction.Member, State)>
For example:
<assembly: FileIOPermission(SecurityAction.Demand, Unrestricted := True)>
<FileIOPermission(SecurityAction.Request, Unrestricted := True)>
The first security example is valid for the entire assembly; hence, every call in this assembly needs to have the FileIOPermission. You can use the second example for a class or a single method. Only a reference to a class or a call of the method will request the CLR for FileIOPermission.
As the syntax already suggests, using <>, this code is not treated as ordinary code. In fact, as you compile the code to an assembly, the compiler extracts these lines and places them in the metadata part of the assembly. The CLR checks this metadata at different points, such as during the load of the assembly or when a method in the assembly is called. Using declarative security, you can demand, request, or even override permissions, even before the code executes. This gives you a powerful security tool during code and assembly development. However, this also means that you must be aware of the type of permissions you need to request and/or demand for your code.
The second method is imperative security, which becomes a part of your code and can make permission demands and overrides. It is not possible to request permissions using imperative security, because it is not clear at what point the code needs a specific permission. That’s why permission requests are related to identifiable units of code. You might want to use imperative security to check whether the caller has a permission that is specific for a part of the code. For example, just before a conditional part of the code (this might even be triggered by the role-based security) wants to access a file or a registry key, you want to check if the caller has this FileIOPermission or RegistryPermission. The syntax of the imperative security in code for C# is shown in Figure A.3; the security in code for VB.NET is shown in Figure A.4.
Permission permissionObject = new Permission();
permissionObject.Demand();
FileIOPermission checkPermission = new FileIOPermission();
checkPermission.Demand();
Figure A.3: Security in Code: C#
Dim PermissionObject as New Permission()
PermissionObject.Demand()
Figure A.4: Security in Code: VB.NET
Here is an example:
Dim CheckPermission as New FileIOPermission()
CheckPermission.Demand()
The permission object is valid only for the scope on which it is declared; the CLR will automatically discard the object upon leaving the scope of the current procedure. Within this scope, imperative security demands and overrides overrule the permissions demanded with a declarative security statement.
Now that we’ve discussed declarative and imperative security, it’s time to look at how you can use this information to request, demand, and override permissions.
Requesting Permissions
Requesting permissions is the best way to create a secure application and prevent possible misuse of your code by malicious code. As we mentioned before, based on the evidence, an assembly hands over to the CLR, which then determines the permission, based on relevant security policies. You construct these security policies independently from the permissions an assembly needs. Of course, if you fully trust an assembly, you can grant it all the permissions it requires. The CLR can grant an assembly more permissions than it actually needs, but an assembly can explicitly request only those specific permissions that it requires. This creates one of two scenarios:
An assembly requests more permissions than the security policy grants, in which case the CLR will not execute the code and will throw an exception.
An assembly specifically requests fewer permissions and protects itself from potential misuse of unused permissions.
Requesting permissions is a good security practice but demands from the developer a solid understanding of the use of permissions in code. There are three types of permission requests:
RequestMinimum Defines the permissions the code absolutely needs to be able to run. If the RequestMinimum permission is not part of the granted permission set, the CLR does not allow the code to run.
RequestOptional Defines the permissions the code might not necessarily require to run but might need in certain circumstances. If the RequestOptional permission is not part of the granted permission set, the CLR allows the code to run. However, you need the code to be able to handle exceptions in cases where the code requires a permission not granted by the CLR.
RequestRefuse Defines the permissions the code will never need and that should not be granted to the assembly. By refraining from using certain permissions, you limit exposure to security risks from malicious or buggy code.
After the code is completed and you compile assemblies, you should get into the practice of making a minimum, optional, or refuse request for every permission (as listed in Table A.3), based on the permissions the code needs. Eventually, you can make it more specific to relate it to classes or members. Besides the fact that you can create secure assemblies, it is also a good way of documenting the permissions related to your code.
Permission Class | Permission Type | Description |
|---|---|---|
DirectoryServicesPermission | Resource | Controls access to the System.DirectoryServices classes. |
DnsPermission | Resource | Controls access to the DNS servers on the network. |
EnvironmentPermission | Resource | Controls access to the user environment variables. |
EventLogPermission | Resource | Controls access to the event log services. |
FileDialogPermission | Resource | Controls access to files that are selected through an Open File… dialog. |
FileIOPermission | Resource | Controls access to files and directories. |
IsolatedStorageFilePermission | Resource | Controls access to a private virtual file system related to the identity of the application or component. |
MessageQueuePermission | Resource | Controls access to the MSMQ services. |
OleDbPermission | Resource | Controls access to the OLE DB data provider and the data sources associated with it. |
PerformanceCounte Permission | Resource | Controls access to the performance counters of Windows 2000 (or NT). |
PrintingPermission | Resource | Controls access to printers. |
ReflectionPermission | Resource | Controls access to metadata types. |
RegistryPermission | Resource | Controls access to the registry. |
SecurityPermission | Resource | Controls access to SecurityPermission, such as Assert, Skip Verification, and Call Unmanaged Code. |
ServiceControllerPermission | Resource | Controls access to services on the system. |
SocketPermission | Resource | Controls access to sockets that are needed to set up or accept a network connection. |
SqlClientPermission | Resource | Controls access to SQL server databases. |
UIPermission | Resource | Controls access to UI functionality, such as Clipboard. |
WebPermission | Resource | Controls access to an Internet-related resource. |
PublisherIdentityPermission | Identity | Permission is granted if the caller provides the evidence publisher. |
SiteIdentityPermission | Identity | Permission is granted if the caller provides the evidence site. |
StrongNameIdentityPermission | Permission is granted if the caller provides the evidence strong name. | |
UrlIdentityPermission | Identity | Permission is granted if caller provides the evidence URL. |
ZoneIdentityPermission | Identity | Permission is granted if the caller provides the evidence zone. |
Demanding Permissions
By demanding permissions, you force the caller to obtain specific permissions from the CLR. As we discussed before, a permission demand triggers a security stack walk. Even if you do not perform these demands yourself, the .NET Framework classes will perform them on your behalf. This means that you should not demand permissions related to these classes, because they will take care of those themselves. If you do perform a demand, it will be redundant and only add to the execution overhead. This does not mean that you should ignore this function. Instead, be aware of which call will trigger a stack walk, and make sure that the code does not perform unnecessary stack walks. However, when you build your own classes that access protected resources, you need to place the proper permission demands, using the declarative or imperative security syntax.
Using the declarative syntax when making a permission demand is preferable to using the imperative syntax, because the latter might result in more stack walks. Of course, some cases are better suited for imperative permission demands. For example, if a registry key has to be set under specific conditions, you will perform an imperative RegistryPermission demand just before the code is actually called. This also implies that the caller can lack this permission, which will result in an exception that the code needs to handle accordingly. Another occasion in which you want to use imperative demands is when information is not known at compile time. A simple example is FileIOPermission on a set of files whose names are not available at compile time.
The CLR handles two types of demands differently than previously described. First, you can only use the link demand in a declarative way at the class or method level. The CLR performs the link demand only during the JIT compilation phase, in which it checks to see whether the calling code has sufficient permission to link to your code. The CLR does not perform a security stack walk, because linking exists only in a direct relation between the caller and code called. The use of link demands can be helpful to methods that are accessible through reflection. The link demand will not only perform a security check on code that obtains the MethodInfo object—hence, performing the reflection—but the same security check is performed on the code that will make the actual call to the method. Figures A.5 and A.6 show a link demand at class and at method level.
[SecurityPermissionAttribute(SecurityAction.LinkDemand,
Unrestricted = true)]
public class ClassAct
{
[SecurityPermissionAttribute(SecurityAction.LinkDemand)] public int
Act1()
{
// body of method
return 1;
}
}
Figure A.5: Link Demand at Class and Method Level: C#
<SecurityPermissionAttribute(SecurityAction.LinkDemand, _
Unrestricted := True)> Public Class ClassAct
Public Shared Function _
<SecurityPermissionAttribute(SecurityAction.LinkDemand)> Act1() _
As Integer
'' body of the function
End Function
Figure A.6: Link Demand at Class and Method Level: VB.NET
The second type of demand is inheritance demand, which you can use at both the class and method level, through the declarative security. Placing an inheritance demand on a class can prevent other classes from inheriting it unless they
have that specific permission. Although you can use a default permission, it makes sense to create a custom permission to assign to the inheriting class to be able to inherit from the class with the inheritance demand. The same goes for the class that inherits from the inheriting class. For example, let’s say that you have created the ClassAct class that is inheritable but also has an inheritance demand set. You have defined your own inherit permission InheritAct. Another class called ClassActing wants to inherit from your class, but because it is protected with an inheritance demand, it must have the InheritAct permission to be able to inherit. Let’s assume that it does have that permission. Now another class called ClassReacting wants to inherit from the class ClassActing. For ClassReacting to inherit from ClassActing, it also needs to have the InheritAct permission assigned. The inheritance demand would look like Figures A.7 and A.8.
<InheritActAttribute(SecurityAction.InheritanceDemand)> public Class
ClassAct
Figure A.7: Inheritance Demand: C#
<InheritActAttribute(SecurityAction.InheritanceDemand)> Public Class
ClassAct
Figure A.8: Inheritance Demand: VB.NET
The inheritance demand at method level will resemble Figures A.9 and A.10.
[SecurityPermissionAttribute(SecurityAction.InheritanceDemand)] public
virtual int Act1()
{
// body of method
return 1;
}
Figure A.9: Inheritance Demand at the Method Level: C#
Public Overridable Function _
<SecurityPermissionAttribute(SecurityAction.InheritanceDemand)>_
Act1() as Integer
'' Body of the function
End Function
Figure A.10: Inheritance Demand at the Method Level: VB.NET
Overriding Security Checks
Because stack walking can introduce serious overhead and thus performance degradation, you need to keep stack walks under control. This is especially true if they do not necessarily contribute to security, such as when a part of the execution can only take place in fully trusted code. On the other hand, your code has permission to access specific protected resources, but you do not want code that you call to gain access to these resources—so you want to have a way to prevent this. In both cases, you want to take control of the permission security checks, thus overriding security checks. You can do this by using the security actions Assert, Deny, and PermitOnly (meaning “deny everything but”).
After the code sets an override, it can undo this override by calling the corresponding Revert method: RevertAssert, RevertDeny, and RevertPermitOnly, respectively. Get into the practice of first calling the Revert method before setting the override, because performing a Revert on a nonexistent override has no effect.
Assert Override
When you set an Assert override on a specific permission, you force a stack walk on this permission to stop at your code and not continue to check the callers of your method.
| Warning | If you use an Assert, you prevent the CLR from completing security checks, which may be a security risk. If you do this, you must be absolutely sure that there is no way to exploit your code. Nevertheless, you should always avoid using Assert overrides. |
The use of Assert might make sense in the following situations:
You have coded a part of an application that will never be exposed to the outside world. The user of the application has no way of knowing what happens within that part of the application. Your code does need access to protected resources, such as system files and/or registry keys, but because the callers will never find out that you use these protected resources, it is reasonably safe to set an Assert to prevent a full security check from being performed. You do not care whether the caller has that permission or not.
Your code needs to make one or more calls to unmanaged code, but because the caller of the code obtains access through your Web site, you are safe in assuming that he or she will not have permissions to make calls to unmanaged code. On the other hand, the callers cannot influence the calls you make to unmanaged code. Therefore, it is reasonably safe to assert the permission to access unmanaged code.
You know that somewhere in your code you have to perform a search, using a Do..Loop structure that at one point must access a protected resource. You also know that the code that calls the protected resource cannot be called from outside the loop. Therefore, you decide to set an assertion just before the call to the protected resource, to prevent a surplus of stack walks. In case the particular piece of code that does the call to the protected resource can be called by other code, you have to move up the assertion to the code that can only be called from the loop.
Let’s look at the stack walk that was initially used in Figure A.1, but now let’s throw in an assertion and see what happens (see Figure A.11). The Assert is set in Assembly4 on the UIPermission. In the situation with no Assert, the stack walk did not succeed because Assembly1 did not have this permission. Now the stack walk starts at Assembly6, performing a permission demand on UIPermission, and goes on its way as usual. Now the stack walk reaches Assembly4 and recognizes an Assert on the permission it is checking. The stack walk stops there and returns with a positive result. Because the stack walk was short-circuited, the CLR has no way of knowing that Assembly1 did not have this permission.
An Assert can be set using both the declarative and the imperative syntax. In the first example, the declarative syntax is used. An Assert is set on the FileIOPermission.Write permission for the CFG files in the C:\Test directory in Figures A.12 and A.13.

Figure A.11: A Stack Walk Is Short-Circuited by an Assert
[FileIOPermission(SecurityAction.Assert, Write=@"C:\Test\.cfg")]
public int Act1()
{
return 1;
}
int Act1()
{
FileIOPermission ActFilePerm = new
FileIOPermission(FileIOPermissionAccess.Write, @"C:\Test\.cfg");
ActFilePerm.Assert();
return 1;
}
Figure A.12: Setting an Assert: C#
Public Function _
<FileIOPermission(SecurityAction.Assert, Write := "C:\Test\*.cfg")> _
Act1() As Integer
'' body of the function
End Function
Figure A.13: Setting an Assert: VB.NET
The second example uses the imperative syntax setting the same type of Assert:
Public Function Act1() As Integer
Dim ActFilePerm As New _
FileIOPermission(FileIOPermissionAccess.Write, "C:\Test\*.cfg")
ActFilePerm.Assert
'' rest of body
End Function
Deny Override
Deny does the opposite of Assert in that it lets a stack walk fail for the permission on which the Deny is set. There are not many situations in which a Deny override makes sense, but here is one: Among the permissions your code has is RegistryPermission. Now it has to make a call to a method for which you have no information regarding trust. To prevent that code from taking advantage of the RegistryPermission, your code can set a Deny. Now you are sure that your code does not hand over a high-trust permission.
Because unnecessary Deny overrides can disrupt the normal working of security checks (because they will always fail on a Deny), you should revert the Deny after the call ends for which you set the Deny.
For the sake of the example, we use the same situation as in Figure A.11, but instead of an Assert, there is a Deny (see Figure A.14). Again, the security stack walk is triggered for the UIPermission permission in Assembly6. When the stack walk reaches Assembly4, it recognizes the Deny on UIPermission and it ends with a fail. In our example, the security check would ultimately have failed in Assembly1, but if Assembly1 had been granted the UIPermission, the stack walk would have succeeded if not for the Deny. Effectively this means that Assembly4 revoked the UIPermission for Assembly5 and Assembly6.

Figure A.14: A Stack Walk Is Short-Circuited by a Deny
You can set a Deny by using both the declarative and the imperative syntax. In the first example, the declarative syntax is used. A Deny is set on the FileIOPermission permission for all the files in the C:\Winnt\System32 directory in Figures A.15 and A.16.
[FileIOPermission(SecurityAction.Deny, All = @"C:\Winnt\System32\.")]
public int Act1()
{
return 1;
}
int Act1()
{
FileIOPermission ActFilePerm = new
FileIOPermission(FileIOPermissionAccess.AllAccess, @"C:\WinntSystem32\.");
ActFilePerm.Deny();
return 1;
}
Figure A.15: Setting a Deny: C#
Public Function _
<FileIOPermission(SecurityAction.Deny, All := "C:\Winnt\System32*.*")> _
Act1() As Integer
'' body of the function
End Function
Figure A.16: Setting a Deny: VB.NET
The second example uses the imperative syntax setting the same type of Assert:
Public Function Act1() As Integer
Dim ActFilePerm As New
FileIOPermission(FileIOPermissionAccess.AllAccess, _
"C:\Winnt\System32\*.*")
ActFilePerm.Deny
'' rest of the body
End Function
PermitOnly Override
The PermitOnly override is similar to the negation of the Deny by denying every permission but the one specified. You use the PermitOnly for the same reason you use Deny, only PermitOnly is more rigorous. For example, if you permit only the UIPermission permission, every security stack walk will fail but the one that checks on the UIPermission.
For example, take Figure A.14 and substitute Deny with PermitOnly. If in Assembly6 the security check for UIPermission is triggered, the stack walk will pass Assembly4 with success but will ultimately fail in Assembly1. If any other security check is initiated, it will fail in Assembly. The result is that Assembly5 and Assembly6 are denied any access to a protected resource that incorporates a Demand request, because every security check will fail.
As you can see, PermitOnly is a very effective way of killing any aspirations of called code in accessing protected resources and is used in the same way as Deny and Assert.
Custom Permissions
The .NET Framework enables you to write your own code access permissions, even though the framework comes with a large number of code access permission classes. Because these classes are meant to protect the protected resources and code that are exposed by the framework, it might well be the case that the application you are developing has defined resources that are not protected by the framework permissions, or you might want to use permissions that are more tuned to your application’s needs.
You are completely free to replace existing framework permission classes, although doing so requires a large amount of expertise and experience. In case you are just adding new permission classes to the existing ones, you should be particularly careful not to overlap permissions. If more than one permission protects the same resource or operation, an administrator has to take this into account if he or she has to modify the rights to these resources.
Building your own permissions not only implies that certain development issues are raised, but even more so, the integrity of the entire security system must be discussed. You have to take into account that you are adding to a rigid security system that relies heavily on trust and permissions. If mistakes occur in the design and/or implementation of a permission, you run the risk of creating security holes that can become the target of attacks or let an application grant access to protected resources that it is not authorized to access. Discussing the process of designing your own permissions goes beyond the scope of this appendix. However, the following steps give you an understanding of what is involved in creating a custom permission:
Design a permission class.
Implement the interfaces IPermission and IUnrestrictedPermission.
In case special data types have to be supported, you must implement the interface ISerializable.
You must implement XML encoding and decoding.
You must implement the support for declarative security.
Add Demand calls for the custom permission in your code.
Update the security policy so that the custom permission can be added to permission sets.