Jump to navigation

Poupou's Corner of the Web

Looking for perfect security? Try a wireless brick.
Otherwise you may find some unperfect stuff here...

Weblog

Mono Security Manager Part III - Using Non-CAS permissions

Are there such things as non-CAS permissions ? Well I surely hope so, code security is fairly new compared to Role-Based Access Control (RBAC) or any arbitrary permission (e.g. time based). But technically the CLR doesn't make much difference of them and most differences are hidden to developpers.

So what are the technical differences between CAS and non-CAS permissions ?

  • All CAS permissions classes inherits from System.Security.CodeAccessPermission. This means they implement both the IPermission and the IStackWalk interfaces;
  • Non CAS permissions don't have to inherit from any specific class but must implement the IPermission interface. The only example in the framework is the PrincipalPermission class - a classic RBAC example;
  • As non CAS permissions do not implement the IStackWalk interface they cannot be used to Assert, Deny or PermitOnly (i.e. the stack modifiers). In fact they do not provoke a stack walk at all.

Non CAS permission have been working for a while on Mono. In fact this sample, with a few subtle changes, would work under Mono 1.0.x. The subtlety is that we can now use declarative security syntax (i.e. attributes) instead of using imperative security (i.e. source code).

To be used for declarative security, a permission class must have a corresponding security attribute class (e.g. PrincipalPermissionAttribute). The attribute class must inherit from SecurityAttribute, otherwise it attribute will be encoded as a custom attribute (i.e. the security manager won't execute it). Now just to confuse things all security attributes do not inherit directly from SecurityAttribute but from CodeAccessSecurityAttribute - even non CAS permissions (note that the class isn't named CodeAccessPermissionAttribute after all ;-).

The following sample restrict execution of the Execute method to the user named root. Unlike my two previous blog entries, it doesn't restrict a specific resource or something specific to the assembly (i.e. code identity), but the user itself.

using System; using System.Security; using System.Security.Permissions; using System.Security.Principal; using System.Threading; public class Program { [PrincipalPermission (SecurityAction.Demand, Name="root")] public void Execute () { Console.WriteLine ("Welcome {0}", Environment.UserName); } static void Main () { Console.WriteLine ("Security is {0}", SecurityManager.SecurityEnabled ? "ON" : "OFF"); // note 1: PrincipalPolicy.WindowsPrincipal work as well for POSIX with Mono // note 2: AppDomain.SetPrincipalPolicy requires the ControlPrincipal right. // so a Demand/stackwalk is being done just before our sample starts... AppDomain.CurrentDomain.SetPrincipalPolicy (PrincipalPolicy.WindowsPrincipal); try { new Program ().Execute (); } catch (SecurityException) { Console.WriteLine ("Program limited to 'root' user."); Console.WriteLine ("You are currently logged as '{0}'.", Thread.CurrentPrincipal.Identity.Name); } } }

Now compile the sample, try to execute it without the security manager, then execute it with the security manager and finally execute it as root with the security manager still enabled...

> mcs root.cs > mono root.exe Security is OFF Welcome poupou > mono --security root.exe Security is ON Program limited to 'root' user. You are currently logged as 'poupou'. > su -c "mono --security root.exe" Password: ******** Security is ON Welcome root

So the security manager does more then just handle CAS. But CAS is so big that most people don't make any distinction between CAS and the security manager. As I said before the framework itself doesn't help much in making a distinction, let's try a variation: Insert a line to disable the SecurityManager just before calling the Execute method...

try { // Insert the next line SecurityManager.SecurityEnabled = false; new Program ().Execute (); }

and execute it again, as yourself and as root, with the security manager enabled...

> mono --security root.exe Security is ON Program limited to 'root' user. You are currently logged as 'poupou'. > su -c "mono --security root.exe" Password: ******** Security is ON Welcome root

and the PrincipalPermission still gets called! It's not a Mono specific behavior but don't trust me just because I wrote this on the internet, go ahead and try it on the MS framework ;-). The "security manager" is an overloaded keyword in the CLR. Also note that on Mono it won't work (i.e. it won't get called) if you do not enable the security manager.

This leads to an important feature, supplying the --security to Mono means more than just turning on the SecurityManager.SecurityEnabled property. The reverse is also true, and potentially more dangerous, not enabling the security manager disable more security than turning off the SecurityManager.SecurityEnabled property!

Q&A

Q - What happens if I use a [PrincipalPermission(...)] in my code and execute it with Mono 1.0.x or before Mono 1.1.4 ?

A - It will be ignored as any type (CAS or non-CAS) of declarative security. In fact it will also be ignore with 1.1.4 onward if you do not activate the security manager (--security).

Q - Can non-CAS permission be used for LinkDemand (JIT time) and InheritanceDemand (load time) ?

A - PrincipalPermission wouldn't be very useful, but it's still usable. Other custom non-CAS permission could be more useful.


There is much more to say (and do) on CAS but the last three entries covers what's available in Mono 1.1.4, so I'll probably keep quiet on CAS until 1.1.5 is released with even more goodies ;-).


2/23/2005 18:58:29 | Comments | Permalink

Mono Security Manager Part II - Using Code Identity Permissions

Yesterday I showed a sample which demanded a resource permission, UnmanagedCode in order to call Environment.Exit. Today I'll do something very similar with an identity permission.

If you have read Keith's article then you have seen the difference between the resource (e.g. file, registry, sockets...) and the identity (e.g. url, hash, zone...) permissions - aptly named *IdentityPermission. If not the previous examples should be enough to give you an idea ;-)

The following sample is based on the most commonly used identity permission, at least in source code, the StrongNameIdentityPermission. This identity permission allows you to control access based on the presence (or absence) of a digital signature on the assembly (or assemblies [1]).

As a first step, we need to create a new key pair for this sample. This key pair will let us sign our sample assembly later.

> sn -k identity.snk Mono StrongName - version 1.1.4.0 StrongName utility for signing assemblies Copyright 2002, 2003 Motus Technologies. Copyright 2004-2005 Novell. BSD licensed. A new strong name keypair has been generated in identity.snk

Next we need to extract the public key from the identity.snk file so we can include it in our application source code.

> sn -tp identity.snk Mono StrongName - version 1.1.4.0 StrongName utility for signing assemblies Copyright 2002, 2003 Motus Technologies. Copyright 2004-2005 Novell. BSD licensed. Public Key: 0024000004800000940000000602000000240000525341310004000011000000e93f54e8ace78c 04da3c4d57f0fad017ddc95d0213af383927fd143f7cac6acc17277b55864a5c9ffb1b1887c6e5 bbfb4a78c6fa10934c48aa815949e5279e17d3cb50f10779aa4bc75f58cb4acfbcd03037638d1d 32c4fd70a2e1a891d8c0046d3121705cfcd226f8fb8bc1965c7597c3ddc31d7f01aedfe800b8b1 5d344280 Public Key Token: 68cd852287e11fbb

Now the source code...

using System; using System.Security; using System.Security.Permissions; using System.Security.Principal; using System.Threading; public class Program { // substitute your own public key [StrongNameIdentityPermission (SecurityAction.Demand, PublicKey="00240000048...")] public void Execute () { Console.WriteLine ("Ok"); } static void Main () { Console.WriteLine ("Security is {0}", SecurityManager.SecurityEnabled ? "ON" : "OFF"); try { new Program ().Execute (); } catch (SecurityException) { Console.WriteLine ("Can't execute - assembly isn't strongnamed!"); } } }

Note: You need to replace the incomplete PublicKey property with the one you generated with the sn tool.

The sample will only allows [2] the Execute method to be executed if the assembly has the corresponding public key.

Note that I didn't said "if the assembly is signed"! This isn't the identity permission job to check if the identity is valid (or not). Identities are supplied by the runtime as evidences to evaluate the security policies - so it is the runtime job to ensure the evidence are valid before supplying them. This also means that no cryptographic operation (e.g. signature verification) are required each time a StrongNameIdentityPermission is being checked.

Now we compile this sample without signing the resulting assembly. We can then execute the sample with and without the security manager.

> mcs identity.cs > mono identity.exe Security is OFF Ok > mono --security identity.exe Security is ON Can't execute - assembly isn't strongnamed!

So the security manager, if active, does it's job not to execute the Execute method if no public key is present in the assembly.

Now recompile the sample this time signing the resulting assembly and execute the sample (again with and without the security manager).

> mcs identity.cs /keyfile:identity.snk

Note: the /keyfile switch is available for MCS (1.x) and CSC 8.x (fx 2.0). This means that you must add [assembly: AssemblyKeyFileName ("identity.snk")] in the sample's source code for CSC 7.x (fx 1.0/1.1).

> mono identity.exe Security is OFF Ok > mono --security identity.exe Security is ON Ok

In this case the security manager, when active, did a stack walk, because the security action is a Demand, and found out that all assemblies on the stack had the required StrongName to allow execution of the Execute method.

So far it's very much like using resource permissions, but it's not yet over...

[1] Pitfalls

Code Identity Permissions are rarely used with "classic" Demands (as we do in this sample). This is because a stack walk requires all assemblies (on the stack) to succeed the security check. In this case this requires all assemblies to share the same strongname (identity). This may happens if you use a Zone identity but it's unlikely to be true for most others - like StrongNames. The reason this sample works is that only one assembly is present on the stack when the demand is executed by the security manager.

Now that doesn't mean identity permission aren't useful - they just aren't much used with a standard (stack walk) Demand. However they are far more useful when used with LinkDemand, evaluated at JIT time, or with InheritanceDemand, evaluated at load time (both unavailable in Mono 1.1.4 but present in SVN HEAD). Something to blog on later...

[2] Looking forward: Fx 2.0

A very important fact to be aware is that version 2.0 of the .NET framework will be introducing a big change for identity permissions: they will become unrestricted permissions like the resources permissions. Which means that this sample, when executing on 2.0, will work even if the assembly isn't signed!

Why ? Because the application is local, so it is, by default, running at FullTrust. Full trust implies that you have unrestricted access to ressources (in 1.x) and now (in 2.0) that identity permission are unrestricted permissions, unrestricted access to identities.

This means that anyone using identity permissions as a code access control mechanisms for fully trust code (e.g. a plugin system based on strongnames for digital signature and enforced by the runtime/security manager) will loose this feature soon. And yes this also means that any (fully trusted) code can now inherit/override from (InheritanceDemand) or call (LinkDemand) into the class library - so it doesn't just unprotect your code.

Now I may not like it but this isn't as bad as it sounds. There were already ways to fool around such protections. Some (most?) people were putting too much confidence into them (hey! you're still dealing with fully trusted code). Some other (not too serious - even if they don't know it) people were even claiming to have broken .NET security because of this. Conclusion: the code is running at FullTrust so it should be and will now be fully trusted ;-).

Next stop... non-CAS permissions aren't oximorons!


2/22/2005 10:04:00 | Comments | Permalink

Mono Security Manager Part I - Using CAS permissions

Here's the first promised CAS sample for Mono.

using System; using System.Security; using System.Security.Permissions; public class Program { public void Quit (int rc) { Console.WriteLine ("Trying to quit with {0}...", rc); // this requires permission to execute unmanaged code Environment.Exit (rc); } [SecurityPermission (SecurityAction.Deny, UnmanagedCode=true)] public void Loop () { while (true) { Console.Write ("> "); switch (Console.ReadLine ().ToLower ()) { case "endloop": // quit loop return; case "quit": try { Quit (1); } catch (SecurityException se) { Console.WriteLine (se.ToString ()); } break; default: Console.WriteLine ("* Unknown command. Try 'quit' or 'endloop'"); break; } } } static void Main () { Console.WriteLine ("Security is {0}", SecurityManager.SecurityEnabled ? "ON" : "OFF"); Program p = new Program (); p.Loop (); // if we're running at FullTrust (default) then this will work // without problem (i.e. no SecurityException) p.Quit (0); } }

As you can see the sample is quite simple - the Loop method denies any request to call unmanaged code. Either via directly using P/Invoke or by using framework methods that requires the privilege to call unmanaged code. The later case is being demonstrated in the sample when calling the Environment.Exit static method.

Here's the definition for System.Environment.Exit(Int32):

[MethodImplAttribute (MethodImplOptions.InternalCall)] [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)] public extern static void Exit (int exitCode);

First line:
The MethodImplOptions.InternalCall indicates that the actual implementation of the method resides in the Mono runtime. The security manager doesn't enforce any restriction to execute this icall because the type, Environment, and the method, Exit are both public and because Mono 1.1.4 doesn't (yet) enforce restrictions on calling runtime's icalls (but this feature is already in SVN for HEAD users).

Second line:
The security manager (if active) will initiate a stack walk to ensure that all callers on the stack have the rights to call unmanaged code. In this case both the executing assembly (e.g. exit.exe) and mscorlib.dll are in the local file system and are granted FullTrust. This means that, under normal condition, the call to Exit should succeed.

Third line:
The definition of the method call.

Now let's compile the sample code and try to execute it without enabling the security manager.

> mcs exit.cs > mono exit.exe Security is OFF >

The sample starts by indicating the status of the security manager. In this case (OFF) nothing can stop you from quiting the application before ending the loop. Type quit followed by ENTER to quit the sample. While this isn't a big problem when running an application at FullTrust it's more a problem if you are hosting mono inside your application (e.g. a database server supporting C# stored proc) or if you have a plug-in system.

Next execute again the sample code with the security manager enabled:

mono --security exit.exe Security is ON >

In this case (ON) the security manager will stops you from quitting the application directly from inside the loop (i.e. where the Deny declarative security attribute applies). Type quit followed by ENTER. You should see the text from the SecurityException thrown from the security manager. Now type endloop followed by ENTER to quit the sample.

Note that this sample isn't very secure (i.e. don't use that pattern) as the loop is still running at FullTrust - there are much better way to sandbox code than to use Deny. You will also get the same behaviour (by default) using MS Framework on Windows. However calling "exit" in a Windows' shell will close the shell - not execute the program - so be sure to specify the ending .exe in the command line.

Now this sample works because Demand (i.e. stack walks) is functional in Mono 1.1.4 as are the declarative stack modifiers (e.g. Deny) and most important because I added the proper security checks (either in declarative or imperative form) to the System.Environment class before the 1.1.4 release. This means that similar cases with different classes won't work because there is no security permission to protect them (yet)! But nothings stops you from adding permissions into your own code today ;-)

Next stop... identity permissions!


2/21/2005 08:51:50 | Comments | Permalink

New security features in Mono 1.1.4

Rejoy! Mono 1.1.4 is out and full of new goodies :-)

CAS

The most interesting feature, at least from my point of view ;-), is that Code Access Security (CAS) can now be used with Mono. This is the first version were end-users can see visible progress since CAS first steps last summer.

Mono 1.1.4 supports a new --security switch to enable the security manager - which is responsable (among other things) for CAS. The security manager allows stack walks, and other security actions, to occurs when permissions are demanded either by the user or the runtime itself. This is still a work in progress and very few permissions are present at this time in the class library but the core is there! More details about what you can (and can't) do with CAS next week...

In the mean time, and if you want to learn more about CAS in general, I suggest you read the recent article "An Introduction to Code Access Security" from Keith Brown on MSDN.

New and updated tools

The certmgr tool has been updated to download certificates, including up-to the root certificate if desired.

certmgr.exe -ssl https://www.verisign.com

This can be done from any SSL session (as long as you supply the port number for non-Fx protocol), e.g.

certmgr -ssl ldaps://www.nldap.com:636

There are a few possible problems (like old root certificates using MD2 in their signature) so be sure to read the man page if it doesn't work.

Other recent security tool additions are caspol.exe to edit Code Access Security policies for Mono (not well tested at this stage) and permview.exe to display the declarative security attributes inside an assembly. The current permview.exe is rather limited but a future Cecil-based version will do a lot of cool stuff.


2/18/2005 16:25:22 | Comments | Permalink

Another one bites the dust

After MD5 last year, it's SHA-1 turn to disappoint us. SHA-1 isn't as good as expected - at 2^69 it's a long way from the advertised 2^80. I guess it's time to review your usage (direct or indirect) of the algorithm.

We're facing an endangered spece when individuals from a spece dies faster than they reproduce. We're sure facing this problem today with hash algorithms. Another analogy is the poor genetic pool, the fact that the SHA-2 family is related to SHA-1. So it's not clear (at least now) how much of the problem the SHA-2 algorithms (SHA-256/224 and SHA-512/384) have inherited.

Not much I can do myself for this problem :-(. Let's hope this news will encourage more people to look for new alternatives...

In the not much category I reopened the SHA-224 support suggestion for framework 2.0 at Microsoft. Please take a few seconds to vote for it. On the bright side support for SHA-224 is already available in Mono.Security.dll (for both Mono and MS runtime users). I'll also update Monodoc with the appropriate warnings...

Addendum: Thanks to the jackson specy for correcting my english ;-)


2/16/2005 12:13:17 | Comments | Permalink

The views expressed on this website/weblog are mine alone and do not necessarily reflect the views of my employer.