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 CAS - A more interesting sample

I've been cleaning up the System.Security.Permissions and System.Security.Policy classes for the last two weeks. Many small issues were fixed in the process, which in turns let us runs more useful samples.

Today I got to run the MSDN documentation sample for PermissionSet. This is a nice one because, like the previous sample, it involves only CAS Demand but it also use all set-operations, Intersect, IsSubsetOf and Union, between different permission types: FileDialogPermission and EnvironmentPermission.

Here the results on Linux:

Executing PermissionSetDemo Adding permission to open a file from a file dialog box. Demanding permission to open a file. Demand succeeded. Adding permission to save a file from a file dialog box. Demanding permission to open and save a file. Demand succeeded. Adding permission to read environment variable USERNAME. Demand succeeded. Adding permission to read environment variable COMPUTERNAME. Demand all permissions. Demand succeeded. Number of permissions = 2 IsSynchronized property = False IsReadOnly property = False SyncRoot property = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.FileDialogPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="COMPUTERNAME"/> </PermissionSet> ContainsNonCodeAccessPermissions method returned False Value of the permission set ToString = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.FileDialogPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="COMPUTERNAME"/> </PermissionSet> Second permission IsSubsetOf first permission = True The intersection of the first permission set and the second permission set = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="COMPUTERNAME"/> </PermissionSet> The union of permission set 3 and permission set 4 = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="COMPUTERNAME"/> <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Append="/home/poupou/src/cas/msdnlib/SomeFile" Read="/home/poupou/src/cas/msdnlib/SomeFile" Write="/home/poupou/src/cas/msdnlib/SomeFile"/> </PermissionSet> The last permission set after removing FileIOPermission = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="COMPUTERNAME"/> </PermissionSet> Permission set after SetPermission = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="USERNAME"/> </PermissionSet> Result of ToFromXml = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="USERNAME"/> </PermissionSet> <IPermission class="System.Security.Permissions.FileDialogPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="COMPUTERNAME"/> Permission set is unrestricted = True Result of copy = <PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="USERNAME" Write="USERNAME"/> </PermissionSet>

Results on Windows (MS runtime) are 100% compatible but not identical due to the ordering of the permissions and the path separators used.

PermissionSet turned out to be a bit more complex than anticipated as it must deal with permissions that do not implement the IUnrestrictedPermission interface (e.g. all identity permissions) which affects all set operations. Also PermissionSet.Demand must take care about non-CAS permissions, like PrincipalPermission and avoid the stack walk if possible.

Oops I almost forgot that I needed your help! The default policies used by the framework are really simple compared to what the .NET framework is capable of. I'd like to know if you, or your company, use any custom policies (entreprise, machine or user specific) or if you have coded any appdomain specific policies. If possible I'd like the XML policies files (cleaned) and/or details of the appdomain policy to plan for the CAS test suite. Thanks :-).


8/31/2004 19:41:44 | Comments | Permalink

First CAS sample in Mono

I've been working on Mono's Code Access Security (CAS) since being back from vacations. This is, like cryptography, not a very visual-friendly task - but there's still some progress to be shown ;-)

If you compile the following source file...

using System; using System.Security; using System.Security.Permissions; using System.Security.Policy; public class Program { static void Demand (SecurityZone zone) { try { new ZoneIdentityPermission (zone).Demand (); Console.WriteLine ("Zone {0}: GRANTED", zone); } catch (Exception e) { Console.WriteLine ("Zone {0}: {1}", zone, e.GetType ()); } } static public void Main (string[] args) { Demand (SecurityZone.Internet); Demand (SecurityZone.Intranet); Demand (SecurityZone.MyComputer); Demand (SecurityZone.NoZone); Demand (SecurityZone.Trusted); Demand (SecurityZone.Untrusted); Demand ((SecurityZone)128); } }

... you will get the following output using either Microsoft's runtime or Mono (CVS):

Zone Internet: System.Security.SecurityException Zone Intranet: System.Security.SecurityException Zone MyComputer: GRANTED Zone NoZone: GRANTED Zone Trusted: System.Security.SecurityException Zone Untrusted: System.Security.SecurityException Zone 128: System.ArgumentException

Now while we're still a very long way from complete CAS support but this little subset is an important milestone because:

  • it shows that (a least a subset) of the security policy can be resolved;
  • it use the host provided evidences to get the current zone (MyComputer) from which the code is being executed;
  • it works using a partial (assembly-based) stack walk.

Best of all it allows to tests many security classes, like permissions, using different policies - something not easily achievable using NUnit. It also open up the doors for more people to start experimenting with CAS, albeit in a very limited form right now, with the next Mono release (1.1.1).

Still missing...

  • full stack walk - required to support modifiers like Assert, Deny and PermitOnly;
  • support for declarative security (attributes);
  • tests;
  • tools like caspol.exe and permview.exe;
  • more tests;
  • the class librairies audit - to ensure correct security attributes are applied;
  • and even more tests.


8/17/2004 09:32:28 | Comments | Permalink

TMW#1 - PEM encoded X.509 certificates

Sometimes, well often enough, people will warn you about P/Invoking. This mostly can be resumed to "we will limit ourselves to an absolute minimum". This is a great advice but it's rarely found in the companion sample code ;-) but sometimes it's true!

There is a lot of interesting, but mostly unmanaged, stuff in the MSDN article "EncryptTo/DecryptTo: Encryption in .NET with CryptoAPI Certificate Stores". It's also a very good example of the P/Invoke portability problem. CryptoAPI has a lot to offer, both in cryptography and in certificate creation/management but it is a Windows-only API.

In some aspects, like cryptography, the current .NET framework (1.1) as more to offer than CryptoAPI, but certificate-wise you won't be impressed by the framework support (thanksfully this is gonna get alot better when the v2 of the framework becomes available).

Anyway let's start with an easy (code wise) sample. X.509 certificates can be encoded in many formats. The most common encoding, on Windows, is the ASN.1 DER binary encoding. It is also the only format supported by the .NET framework (unless you work with Authenticode). However PEM (a.k.a base64) encoded X.509 certificates are quite common - at least outside Windows.

PEM stands for Privacy Enhanced Mail which is a set of RFC (1421, 1422, 1423 and 1424) published in the early '90 to secure email. Most of it is now history and has been superseded by S/MIME or PGP but it's 7-bits ASCII format to encode certificates (and other objects like CRL and private keys) is still around.

I bet you can find a lot of old code, in fact I guess all certificate libraries must include it, to convert from PEM to DER. At least you could do it with CryptoAPI (but you will then be limited to Windows), OpenSSL... In fact it's so simple that you could not bother googling and roll your own in managed code like this.

static byte[] PEM (string type, byte[] data) { string pem = Encoding.ASCII.GetString (data); string header = String.Format ("-----BEGIN {0}-----", type); string footer = String.Format ("-----END {0}-----", type); int start = pem.IndexOf (header) + header.Length; int end = pem.IndexOf (footer, start); string base64 = pem.Substring (start, (end - start)); return Convert.FromBase64String (base64); } static X509Certificate LoadCertificateFile (string filename) { X509Certificate x509 = null; using (FileStream fs = File.OpenRead (filename)) { byte[] data = new byte [fs.Length]; fs.Read (data, 0, data.Length); if (data [0] != 0x30) { // maybe it's ASCII PEM base64 encoded ? data = PEM ("CERTIFICATE", data); } if (data != null) x509 = new X509Certificate (data); } return x509; }

Note: the source code has been extracted from the certmgr.exe tool in Mono.

Sometimes it can easier and faster to read a specification and code it yourself than to find the right library to P/Invoke. PEM-encoded certificates are a good example of this but PKCS#7 certificates, or certificate chains and PKCS#12 are better left to ASN.1 fans ;-)


8/12/2004 20:16:18 | Comments | Permalink

The Managed Way

Hey it's me again! I've been planning for a long time to move my blog to another web site but, as I didn't have the time to do so during my vacations, I decided that it was better to blog here than not blog at all - YMMV.

Looking back at my previous posts it became clear that there were certain patterns to what I did. First it's (mostly) about security. It's also about ".NET and it's nice managed world" or, it's dark side "it's not always easier, or safer, to P/Invoke our way". Or is it ?

P/Invoking is a great and easy way to reuse existing code. So easy in fact this a probably one of the major advantage of .NET over Java. And it's still becoming easier everyday with sites like pinvoke.net.

So what's the catch ? Well P/Invoking isn't without problems. The invoked resources aren't managed (e.g. different versioning, i18n, binary portability) and pose security risks. This is why calling unmanaged code requires a high-level of trust on the executing assembly. This in turns limits your code reusability because you never know under which context your code may be running in a few years.

However the biggest catch is that, P/Invoking being so easy, many people don't even look if a managed solution exists to address their problem (and choose the best one of course). They will either fallback on what they know or on what they can google quickly. I can't do anything about what people know (and wouldn't even if I could ;-) but I seem to google my name (too) often when looking at anything related to ".NET security". Maybe blogging some samples, or alternatives to existing samples, would be useful for them.

Note: I'll limit myself to (mostly) security related samples but feel free to blog on the same pattern for anything you can find :-)


8/11/2004 20:03:17 | Comments | Permalink

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