Welcome to MSDN Blogs Sign in | Join | Help

CLR v4 Security Policy Roundup

Over the last few weeks we’ve been taking a look at the updates to the CLR security policy system in the v4 release of the .NET Framework.  Here’s a quick index of those topics:

Posted by shawnfa | 1 Comments
Filed under: , , ,

Temporarily re-enabling CAS policy during migration

Over the last few weeks we’ve been looking at the changes to security policy in .NET 4, namely that security policy is now in the hands of the host and the operating system.

While we’ve looked at how to update code that implicitly uses CAS policy, loads assemblies from remote sources, and explicitly uses CAS policy, in applications of larger size it may not be practical to update all the code at once.  Similarly, you might be able to update the code in your application, but may rely on a third party assembly that is not yet updated for the changes in CAS policy.

If you do find yourself needing to re-enable CAS policy temporarily, in order to move a large code base to the new v4 security APIs bit by bit rather than all at once, or to use an assembly that you don’t control, there is a configuration switch that you can set in order to flip your process back into legacy CAS policy mode.

In order to temporarily enable legacy CAS policy in your process, you’ll need an .exe.config file for your application with the legacy security policy switch set in its runtime section.  So, if your application’s entry point is YourApp.exe, you’ll have next to it a YourApp.exe.config file.  (You can also use the app.config feature in your Visual Studio project).  The file should look like this for any release of the .NET Framework v4 after beta 1:

<configuration>

  <runtime>

    <NetFx40_LegacySecurityPolicy enabled="true" />

  </runtime>

</configuration>

In .NET 4 Beta 1, the switch has a slightly different name:

<configuration>

  <runtime>

    <legacyCasPolicy enabled="true" />

  </runtime>

</configuration>

One thing to note is that this switch must be set on the process-level.  So, if you’re using a third party control that uses CAS policy, you may well need to set the switch for both Visual Studio in devenv.exe.config and for your application itself.  That way the control will work both in the Visual Studio process during your development, as well as in your process at runtime.

Posted by shawnfa | 1 Comments
Filed under: , , ,

Coding with Security Policy in .NET 4 part 2 – Explicit uses of CAS policy

Over the last few posts, I’ve been looking at how the update to the CLR v4 security policy interacts with how you write managed code against the v4 .NET Framework.  So far we’ve looked at the implicit uses of CAS policy, such as loading assemblies and creating AppDomains with Evidence and loading assemblies from remote sources.  Now let’s look at how to work with code which was written to work with CAS policy explicitly.

The good news is that explicit use of CAS policy is frequently very easy to spot, as opposed to implicit uses which can be somewhat more subtle.  APIs that directly manipulate policy (such as SecurityManager.ResolvePolicy) as well as those that require CAS policy to sandbox (such as AppDomain.SetAppDomainPolicy) fall into this category.  Other APIs that explicitly use CAS policy are:

  • AppDomain.SetAppDomainPolicy
  • HostSecurityManager.DomainPolicy
  • PolicyLevel.CreateAppDomainLevel
  • SecurityManager.LoadPolicyLevelFromString
  • SecurityManager.LoadPolicyLevelFromFile
  • SecurityManager.ResolvePolicy
  • SecurityManager.ResolveSystemPolicy
  • SecurityManager.ResolvePolicyGroups
  • SecurityManager.PolicyHierarchy
  • SecurityManager.SavePolicy

As with the implicit CAS policy uses, the explicit APIs also are obsolete in .NET 4, and will throw NotSupportedExceptions by default:

System.NotSupportedException: This method uses CAS policy, which has been obsoleted by the .NET Framework. In order to enable CAS policy for compatibility reasons, please use the NetFx40_LegacySecurityPolicy configuration switch. Please see http://go.microsoft.com/fwlink/?LinkId=131738 for more information.

Let’s take a look at how code which used these APIs in the past might get updated with new v4 APIs.

Generally, there are three reasons that the explicit policy APIs are being used:

  1. The code wants to figure out what the grant set of an assembly or AppDomain is
  2. The code wants to create a sandbox
  3. The code wants to figure out what a safe sandbox is to setup

The correct way way to update the code calling an explicit policy API in v4 depends upon what it was trying to do by calling the API in the first place.  Let’s take a look at each of the reasons for using an explicit policy API in turn and figure out what the replacement code should look like.

Figuring out what the grant set of an assembly or AppDomain is

Sometimes an application or library wants to figure out what the grant set of a particular assembly or domain was and would do so with code similar to:

private PermissionSet GetAssemblyGrantSet(Assembly assembly)

{

    Evidence assemblyEvidence = assembly.Evidence;

    return SecurityManager.ResolvePolicy(assemblyEvidence);

}

 

private bool IsFullyTrusted(Assembly assembly)

{

    PermissionSet grant = GetAssemblyGrantSet(assembly);

    return grant.IsUnrestricted();

}

 

private PermissionSet GetAppDomainGrantSet(AppDomain domain)

{

    Evidence appDomain = domain.Evidence;

    return SecurityManager.ResolvePolicy(appDomain);

}

 

private bool IsFullyTrusted(AppDomain domain)

{

    PermissionSet grant = GetAppDomainGrantSet(domain);

    return grant.IsUnrestricted();

}

This code worked by resolving the assembly or AppDomain’s evidence through CAS policy to determine what would be granted to that particular evidence.  There are a few problems here – for instance, the code doesn’t take into account simple sandbox domains, hosted AppDomains, dynamic assemblies, or assemblies loaded from byte arrays.  (Take a look at AssemblyExtensionMethods.GetPermissionSet() on http://clrsecurity.codeplex.com for code that does take most of the other considerations into account).   These methods also cause a full CAS policy resolution to occur, which is not a cheap operation. 

Instead of requiring people to manually jump through hoops in order to recreate the CLR’s security policy system in v4, we’ve directly exposed the grant sets of assemblies and AppDomains as properties of the objects themselves.  The above code can be replaced with:

private PermissionSet GetAssemblyGrantSet(Assembly assembly)

{

    return assembly.PermissionSet;

}

 

private bool IsFullyTrusted(Assembly assembly)

{

    return assembly.IsFullyTrusted;

}

 

private PermissionSet GetAppDomainGrantSet(AppDomain domain)

{

    return domain.PermissionSet;

}

 

private bool IsFullyTrusted(AppDomain domain)

{

    return domain.IsFullyTrusted;

}

Which has the dual benefit of being more accurate (these properties read the real grant set that the CLR is using, no matter how it was determined), and also being faster than a full policy resolution.

Accessing the PermissionSet property of an AppDomain or an Assembly does require that the accessing code be fully trusted.  The reason is that the permission sets themselves can contain sensitive data.  (For instance, FileIOPermission can contain full path information about the local machine in it).   Partial trust code, however, can use the IsFullyTrusted property.

Creating a Sandbox

I suspect many people who have read this blog already know what I’m going to say here :-)  Instead of using SetAppDomainPolicy to create a sandbox, which suffers from many problems, the replacement API is the simple sandboxing API.  I’ve already covered most of the reasoning for this change when I talked about sandboxing in CLR v4, so let’s look at the final reason that code may have been using CAS policy APIs

Figuring out what a safe grant set is to provide a sandbox

Sometimes a host needs to figure out what is a reasonable set of permissions to assign to a sandbox.  For instance, even though ClickOnce does not use CAS policy, it still needs to figure out if the permission set that the ClickOnce application is requesting is a reasonable set of permissions for it to have.   (For instance, if it’s requesting only the permission to execute, that’s going to be fine, while if an application from the Internet is requesting permission to read and write all of the files on your disk, that’s not such a good idea).

In order to solve this problem in v2, code might look like this:

private bool IsSafeGrantSet(PermissionSet grantSet, Evidence sandboxEvidence)

{

    // Figure out what the CLR's policy system says is safe to give a sandbox

    // with this evidence

    PermissionSet systemGrantSet = SecurityManager.ResolveSystemPolicy(sandboxEvidence);

 

    // We'll consider this safe only if we're requesting a subset of the safe

    // sandbox set.

    return grantSet.IsSubsetOf(systemGrantSet);

}

Since system wide CAS policy (which this code depends upon to determine safety) is deprecated in v4, we need to find a new way to accomplish this goal.

The answer is with a new API called GetStandardSandbox.   GetStandardSandbox is used to have the CLR provide what it considers a safe sandbox grant set for an AppDomain that will host code with the specified evidence.  It’s the CLR’s way of providing suggestions to hosts who are making trust decisions.   One thing that is very important to note is what GetStandardSandbox is not however.

GetStandardSandbox is not a policy API.  This isn’t the CLR applying CAS to evidence in order to modify grant set, and the CLR does not take any external factors such as CAS policy into account when returning its grant set.  Instead, GetStandardSandbox is simply a helper API for hosts which are trying to setup sandboxes.

With that in mind, the way the above code would be written in CLR v4 is:

private bool IsSafeGrantSet(PermissionSet grantSet, Evidence sandboxEvidence)

{

    // Figure out what the CLR considers a safe grant set

    PermissionSet clrSandbox = SecurityManager.GetStandardSandbox(sandboxEvidence);

 

    // We'll consider this safe only if we're requesting a subset of the safe

    // sandbox set.

    return grantSet.IsSubsetOf(clrSandbox);

}

Similarly, if you are a host trying to setup an AppDomain to sandbox assemblies that are coming from the Internet, you might do so this way:

// Find a safe sandbox set to give to assemblies downloaded

// from the internet

Evidence internetEvidence = new Evidence();

internetEvidence.AddHostEvidence(new Zone(SecurityZone.Internet));

PermissionSet clrSandbox = SecurityManager.GetStandardSandbox(internetEvidence);

 

// Create a sandboxed AppDomain to hold them

AppDomainSetup sandboxSetup = new AppDomainSetup();

sandboxSetup.ApplicationBase = DownloadDirectory;

 

AppDomain sandbox = AppDomain.CreateDomain("Internet sandbox",

                                           internetEvidence,

                                           sandboxSetup,

                                           clrSandbox);

Posted by shawnfa | 1 Comments
Filed under: , , ,

More Implicit Uses of CAS Policy: loadFromRemoteSources

In my last post about changes to the CLR v4 security policy model, I looked at APIs which implicitly use CAS policy in their operation (such as Assembly.Load overloads that take an Evidence parameter), and how to migrate code that was using those APIs.   There are another set of assembly loads which cause implicit use of CAS policy, which I’ll look at today – these are loads from remote sources.

For example, in .NET 3.5 the following code:

Assembly internetAssembly = Assembly.LoadFrom(@"http://www.microsoft.com/assembly.dll");

Assembly intranetAssembly = Assembly.LoadFrom(@"\\server\share\assembly.dll");

Will by default load internetAssembly with the Internet permission set and intranetAssembly with the LocalIntranet permission set.   That was because the CLR would internally gather evidence for both assemblies and run that evidence though CAS policy in order to find the permission set to grant that assembly.

Now that the sandboxing model has changed in the v4 CLR, there is no more CAS policy to apply the assembly’s evidence to by default, and  therefore default behavior of both of these loads would be to load the assemblies with a grant set of full trust.

That creates a problem for code which was written before .NET 4 shipped – this code may quite reasonably be expecting that the above assembly loads are safe because the CLR will automatically apply a restricted grant set to the assemblies if they are coming from a remote location.   Now when the code runs in the v4 CLR, the assemblies are elevated to full trust, which amounts to a silent elevation of privilege bug against the .NET 2.0 code which was expecting that these assemblies be sandboxed.  Obviously that’s not a good thing.

Instead of silently granting these assemblies full trust, the v4 CLR will actually take the opposite approach.  We’ll detect that these assemblies are being loaded in such a way that

  1. They would have been sandboxed by the v2 CLR and
  2. Are going to be given full trust by the v4 CLR

Once we detect an assembly load where both of the above conditions are true, the CLR will refuse to load the assembly with the following message:

System.IO.FileLoadException: Could not load file or assembly '<assemblyPath>' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515 (COR_E_NOTSUPPORTED)) --->

System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=131738 for more information.

This exception is saying “The v4 CLR is not going to sandbox the assembly that you’re trying to load, however the v2 CLR would have.  We don’t know if that’s safe in your application or not, so we’re going to fail the assembly load to ensure that your application is secure by default.  However, if this is a safe assembly load, go ahead and enable loading from remote sources for this process.”

That leads to the next question -- how do you know if it is safe to enable loadFromRemoteSources in your application?  This decision generally comes down to applying these tests:

  1. Do you trust the string that you’re passing to Assembly.LoadFrom?
  2. Do you trust the assembly that you’re loading?
  3. Do you trust the server hosting the assembly (and the network path from the server back to your application)?

If you answered yes to all three questions then your application is a good candidate for enabling the loadFromRemoteSources switch.  If you answered no to any of the three questions, then you may need to take further action before enabling the switch and loading the assembly.   (For instance, you may have some application logic to ensure that the string being passed to LoadFrom is going to a server you trust, or your application might download the assembly first and verify it has an Authenticode signature that it trusts).

Let’s look at some examples:

The most straight-forward reason that you would want to enable this is in the case that you know what the assemblies you are loading are, you trust them, and you trust the server that they are hosted on.  For example, if your application is hosted on a share on your company’s intranet, and happens to need to load other assemblies from other shares on the network, you probably want to enable the switch.   (In many cases, this category of applications used to have to fight with CAS policy to get things loaded the way they wanted, now with loadFromRemoteSources set things should just work.)

On the other hand, if you are an application that takes as untrusted input a string which then is passed through to Assembly.LoadFrom, you probably don’t want to enable this switch, as you might be opening yourself up to an elevation of privilege attack via that untrusted input.

Similarly, if your application takes as input an assembly name to LoadFrom, however you trust that input.  (Maybe it comes directly from your application’s user, and there is no trust boundary between the user and your app – for instance, the user is pointing you at a plugin they trust and wish to load in the app), you may also want to enable this switch.

Another consideration to take into account when considering loadFromRemoteSources is that this is a process-wide configuration switch.  This means that it applies to all places in your code which loads assemblies, not just a single LoadFrom call.  If you only trust the inputs to some of your assembly loads, then you may wish to consider not using the loadFromRemoteSources switch and instead take a different approach.

Since the first condition for the NotSupportedException that blocks remote assembly loads is that the load would have been sandboxed by the v2 CLR, one alternate way to enable these loads without setting loadFromRemoteSources for the entire process is to load the assemblies into a domain that you create with the simple sandboxing API.

This will work because even in v2.0, simple sandbox domains never apply CAS policy, and therefore any remote loads in simple sandbox domains would not have required CAS policy to sandbox them.  Since the assemblies would not have used CAS policy in v2, the loads are considered safe to use in v4 as well, and will succeed without the NotSupportedException being thrown.

For example, if you want to enable only a subset of LoadFroms to load assemblies in full trust, if you create a fully trusted simple sandbox, then any assemblies loaded into that sandbox would have the same full trust grant set in v2 as in v4.   (The full trust grant set of the domain applies to all assemblies loaded into it).   This will cause the CLR to allow the loads to proceed in full trust in v4 without having to throw the switch.

// Since this application only trusts a handful of LoadFrom operations,

// we'll put them all into the same AppDomain which is a simple sandbox

// with a full trust grant set.  The application itself will not enable

// loadFromRemoteSources, but instead channel all of the trusted loads

// into this domain.

PermissionSet trustedLoadFromRemoteSourceGrantSet

    = new PermissionSet(PermissionState.Unrestricted);

 

AppDomainSetup trustedLoadFromRemoteSourcesSetup = new AppDomainSetup();

trustedLoadFromRemoteSourcesSetup.ApplicationBase =

    AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

 

AppDomain trustedRemoteLoadDomain =

    AppDomain.CreateDomain("Trusted LoadFromRemoteSources Domain",

                           null,

                           trustedLoadFromRemoteSourcesSetup,

                           trustedLoadFromRemoteSourcesGrantSet);

 

// Now all trusted remote LoadFroms can be done in the trustedRemoteLoadDomain,

// and communicated with via a MarshalByRefObject.

As an example in the opposite direction, maybe your application has mostly loads which are safe to have remote targets, however there are a small handful of places that do need to be sandboxed.  By creating a simple sandboxed AppDomain for those loads, you can then safely set the loadFromRemoteSources switch for the rest of your process.

// Since this application trusts almost all of its assembly loads, it

// is going to enable the process-wide loadFromRemoteSources switch.

// However, the loads that it does not trust still need to be sandboxed.

 

// First figure out a grant set that the CLR considers safe to apply

// to code from the Internet.

Evidence sandboxEvidence = new Evidence();

sandboxEvidence.AddHostEvidence(new Zone(SecurityZone.Internet));

PermissionSet remoteLoadGrantSet = SecurityManager.GetStandardSandbox(sandboxEvidence);

 

AppDomainSetup remoteLoadSetup = new AppDomainSetup();

trustedLoadFromRemoteSourcesSetup.ApplicationBase = GetSandboxRoot();

 

AppDomain remoteLoadSandbox =

    AppDomain.CreateDomain("Remote Load Sandbox",

                           sandboxEvidence,

                           remoteLoadSetup,

                           remoteLoadGrantSet);

 

// Now all trusted remote LoadFroms can be done in the default domain

// with loadFromRemoteSources set, and untrusted loads can be done

// in the sandbox that we just setup.

(Similarly, if the process is in legacy CAS policy mode, the v4 CLR will have the same behavior as the v2 CLR, and there will be no exception).

Let’s say that you’ve considered the security implications and your application is a good candidate to enable loadFromRemoteSources, how do you go about doing so?   Basically, you just provide a .exe.config file for your application with a loadFromRemoteSources runtime switch enabled.   So, if your application’s entry point is YourApp.exe, you’ll want to make a YourApp.exe.config.   (Or use the app.config file in your Visual Studio project).   This configuration file will need to contain runtime section such as:

<configuration>

  <runtime>

    <loadFromRemoteSources enabled="true" />

  </runtime>

</configuration>

This setting will cause the CLR to notice that even though it is going to load an assembly that would have been sandboxed in the v2 runtime, your application has explicitly stated that this is a safe thing to do.   Since your application has said that it understands the security impact of loading from remote locations and it is safe in the context of this application, the CLR will then allow these loads to succeed without throwing a NotSupportedException to block them.

Posted by shawnfa | 5 Comments
Filed under: , , ,

CLR 4 Security on Channel 9

A while back I did an interview with Charles Torre  about the changes to security in CLR v4, and he posted it to the Channel 9 videos site yesterday.

I start out talking about the security policy changes I've been covering here over the last week, and then transition into an overview of some of the transparency changes that I'll be talking about once I finish with the policy changes.

Get Microsoft Silverlight

(The full video is also available here: http://channel9.msdn.com/posts/Charles/Shawn-Farkas-CLR-4-Inside-the-new-Managed-Security-Model/)

Posted by shawnfa | 1 Comments

Visual Studio 10 Security Tab Changes

Kris Makey, who works on the Visual Studio team, has written up a good blog post about the changes you’ll see on the security tab in Visual Studio 10 when it comes to editing permission sets.  He covers what the changes are, and some of the reasons why we worked with the Visual Studio team to make those changes.

Posted by shawnfa | 1 Comments

Coding with Security Policy in .NET 4.0 – Implicit uses of CAS policy

Last week we looked at sandboxing and the v4 CLR – with the key change being that the CLR now defers exclusively to the host application when setting up sandboxed domains by moving away from the old CAS policy model, and moving instead to simple sandboxed AppDomains.

This leads to an interesting situation when your program calls APIs that assume the presence of CAS policy, either implicitly [for example, Assembly.Load(string, Evidence)] or explicitly [for example SecurityManager.PolicyHierarchy].   These APIs require CAS policy in order to return correct results, however by default there is no longer CAS policy to apply behind the scenes anymore.

Let’s take a look at what happens if these APIs are called, and what should be done to update your code to take into account the new security policy model.

(In addition to this blog post, the CLR security test team is preparing a set of blog posts about how they moved our test code base forward to deal with these and other v4 security changes – those posts will provide additional advice about how to replace uses of obsolete APIs based upon the real world examples they’ve seen).

In general, APIs that assume the presence of CAS policy have been marked obsolete, and will give a compiler warning when you build against them:

Microsoft (R) Visual C# 2010 Compiler version 4.0.20506
Copyright (C) Microsoft Corporation. All rights reserved.

obsolete.cs(32,1): warning CS0618: '<API Name>' is
        obsolete: 'This method is obsolete and will be removed in a future
        release of the .NET Framework. Please use <suggested alternate API>. See
        http://go.microsoft.com/fwlink/?LinkId=131738 for more information.'

Additionally, these APIs will throw a NotSupportedException if they are called at runtime:

Unhandled Exception: System.NotSupportedException: This method uses CAS policy, which has been obsoleted by the .NET Framework. In order to enable CAS policy for compatibility reasons, please use the NetFx40_LegacySecurityPolicy configuration switch. Please see http://go.microsoft.com/fwlink/?LinkId=131738 for more information.

(In the beta 1 release, this message is slightly different:)

Unhandled Exception: System.NotSupportedException: This method uses CAS policy, which has been obsoleted by the .NET Framework. In order to enable CAS policy for compatibility reasons, please use the legacyCasPolicy configuration switch. Please see http://go2.microsoft.com/fwlink/?LinkId=131738 for more information.

Let’s take a look at the set of APIs which make implicit use of CAS policy first, and then see what they might be replaced with in a v4.0 application.

The general way to recognize an API which is implicitly using CAS policy is that they tend to take an Evidence parameter which was used to resolve against CAS policy and provide a grant set for an assembly.  For instance:

  • Activator.CreateInstance and Activator.CreateInstanceFrom overloads which take an Evidence parameter
  • AppDomain.CreateInstance, AppDomain.CreateInstanceFrom, AppDomain.CreateInstanceAndUnwrap, and AppDomain.CreateInstanceAndUnwrap overloads which take an Evidence parameter
  • AppDomain.DefineDynamicAssembly overloads which take an Evidence parameter
  • AppDomain.ExecuteAssembly and AppDomain.ExecuteAssemblyByName overloads which take an Evidence parameter
  • AppDomain.Load and AppDomain.LoadFrom overloads which take an Evidence parameter
  • Assembly.Load and Assembly.LoadFrom overloads which take an Evidence parameter

It’s important to note that although these APIs all take Evidence parameters, the concept of Evidence itself is not deprecated and continues to exist (and even enhanced in v4.0 – but that’s another show).  Evidence itself is still a useful tool for hosts to use when figuring out what grant sets they want to give assemblies.  The common thread with these APIs is that they used the Evidence to resolve against CAS policy – and it’s the CAS policy portion that’s been deprecated in v4.

Let’s say that your application is using one of the Evidence-taking overloads of these APIs, and thus had an implicit dependency on CAS policy.  Figuring out what to replace the API call with depends upon what your application was trying to accomplish with the API call.

We’ve found that commonly the goal of calling one of these APIs was not to sandbox the assembly being loaded, but rather to access other parameters on the overload which may not be available without also providing Evidence.  In these cases, you can go ahead and just drop the Evidence parameter from the API.  We’ve ensured that all of the above APIs now have overloads that provide the full set of parameters without requiring an Evidence parameter.

Additionally, in many cases we’ve found that code passes in Assembly.GetExecutingAssembly().Evidence or simply null to the Evidence parameter.  In both of those cases, it’s safe to simply call an overload of the API which does not require an Evidence parameter as well.

The other reason to provide Evidence when calling these APIs is to sandbox the assembly in question.  The correct way to do this in v4 (and the best way to do this in v2.0 and higher of the .NET Framework) is to simply load the assembly into a simple sandboxed AppDomain.  The assembly will then be sandboxed by virtue of the fact that it’s loaded in the sandboxed domain, and you will no longer need to load the assembly with an Evidence parameter to restrict its grant set.

I’ve listed the benefits of using simple sandboxed domains before, and they continue to apply in this scenario.  For example, using a simple sandbox rather than an Evidence resolve to sandbox assemblies allows your application:

  • To be in charge of its own sandbox.  The load-with-Evidence route took a dependency on what the grant set that the CLR would give the assembly was.  That grant set could change from version to version of the CLR (since each version has independent CAS policies), and even from user to user.  This makes supporting your application more difficult than it needs to be – with simple sandboxing there are no external dependencies for grant set resolution – your application is in charge of its own sandboxes
  • To setup real isolation boundaries – hosting multiple levels of partial trust code within a single AppDomain turns out to be incredibly difficult to do correctly.  Further, hosting partial trust code in a domain wtih full trust code that does not expect to be run along with partial trust code also turns out to be problematic from a security perspective.  By isolating the partial trust code in its own sandboxed domain, a real isolation boundary is setup for the code and your application is kept much more secure by default.
  • To have version and bitness independence – I touched on this in the first point, but to reiterate it, your application is no longer dependent upon each version of the CLR’s security policy to be setup in the same way, as well as each bitness of the policy within a single version.

So, to summarize, if you’re using one of the Evidence taking APIs which would have resolved an assembly’s grant set against CAS policy in the past:

Use Replacement
Passing null, Assembly.GetExecutingAssembly().Evidence, or AppDomain.CurrentDomain.Evidence Call an overload which does not require an Evidence parameter.
Using a parameter of the API which was only available on an overload taking an Evidence parameter as well. Call one of the newly added overloads which provides access to your parameter without requiring Evidence.
Sandboxing the assembly being loaded. Load the assembly into a sandboxed AppDomain, and let the domain do the sandboxing.  This will remove the need for the Evidence parameter.

Next time, I’ll look at the explicit uses of CAS policy, and what their replacements should be.

Posted by shawnfa | 4 Comments
Filed under: , , ,

Sandboxing in .NET 4.0

Yesterday I talked about the changes in security policy for managed applications, namely that managed applications will run with full trust - the same as native applications - when you execute them directly.

That change doesn’t mean that managed code can no longer be sandboxed however - far from it.  Hosts such as ASP.NET and ClickOnce continue to use the CLR to sandbox untrusted code.  Additionally, any application can continue to create AppDomains to sandbox code in.

As part of our overhaul of security policy in v4, we made some interesting changes to how that sandboxing should be accomplished as well.  In previous releases, the CLR provided a variety of ways to sandbox code – but many of them were problematic to use correctly.  In the v4 framework, we made it a goal to simplify and standardize how sandboxing should be done in managed code.

One of the key observations we made about sandboxing is that there really isn’t a good reason for the CLR to be involved in the decision as to what grant set should be given to partial trust code.   If your application says “I want to run this code with ReflectionPermission/RestrictedMemberAccess and SecurityPermission/Execution”, that’s exactly the set of permissions that the code should run with.   After all, your application knows much better than the CLR what operations the sandboxed code can be safely allowed to undertake.

The problem is, sandboxing by providing an AppDomain policy level doesn’t provide total control to the application doing the sandboxing.  For instance, imagine you wanted to provide the sandbox grant set of RestrictedMemberAccess + Execution permission.  You might setup a policy level that grants AllCode this grant set and assign it to the AppDomain.   However, if the code you place in that AppDomain has evidence that says it came from the Internet, the CLR will instead produce a grant set that doesn’t include RestrictedMemberAccess for the sandbox.  Rather than allowing safe partial trust reflection as you wanted, your sandbox just became execute-only.

This really doesn’t make sense – what right does the CLR have to tell your application what should and should not be allowed in its sandboxes?  In the v1.x release of the runtime, developers had to go to great lengths in order to ensure they got the grant set they wanted.  (Eric Lippert’s CAS policy acrobatics to get VSTO working correctly is the stuff of legends around the security team – fabulous adventures in coding indeed!).

As many a frustrated application developer found out, intersecting with the application supplied grant set was only the tip of the iceburg when it came to the difficulties of coding with CAS policy.  You would also run into a slew of other problems – such as each version of the CLR having an entirely independent security policy to deal with.

In v2.0, we introduced the simple sandboxing API as a way for applications to say “This is the grant set I want my application to have.  Please don’t mess with it.”.  This went a long way toward making writing an application which sandboxes code an easier task.

Beginning with v4.0, the CLR is getting out of the policy business completely.  By default, the CLR is not going to supply a CAS policy level that interferes with the wishes of the application that is trying to do sandboxing.

Effectively, we’ve simplified the multiple ways that you could have sandboxed code in v3.5 into one easy option – all sandboxes in v4 must be setup with the simple sandboxing API.

This means that the days of wrangling with complicated policy trees with arbitrary decision nodes in them are thankfully a thing of the past.  All that’s needed from here on out is a simple statement: “here is my sandboxed grant set, and here are the assemblies I wish to trust.”

Next time, I’ll look at the implications of this on code that interacts with policy, looking at what you used to write, and what it would be replaced with in v4.0 of the CLR.

Posted by shawnfa | 6 Comments
Filed under: , , ,

Security Policy in the v4 CLR

One of the first changes that you might see to security in the v4 CLR is that we’ve overhauled the security policy system.  In previous releases of the .NET Framework, CAS policy applied to all assemblies loaded into an application (except for in simple sandbox domains).

That lead to a lot of interesting problems.  For instance, one of the more common issues people ran into was that they would develop an application on their local machine that they wanted to share with other people on the network.   Once the application was working on their machine, they would share it out, but nobody could run it over the network because CAS policy provided a lower grant set to assemblies loaded from the intranet than it does to assemblies loaded from the local machine.   The usual result was unexpected and unhandled SecurityExceptions when trying to use the application.

Generally, the only solution to this problem was to either manually update the CAS policy on each machine that wanted to run the application, deploy the application some other way (for instance via ClickOnce), or use native code.

One of the worst things about this problem was that the additional pain of not being able to just share a managed app over the network wasn’t actually buying any security.  If an application wanted to attack your machine, it could bypass the sandbox that the CLR was setting up simply by being written in native code.

Effectively, running an executable is a trust decision – you’re saying that you trust the application that you’re running enough to execute with the privileges your Windows account has.

That leads to an interesting observation – the CLR isn’t the correct place to be setting permission restrictions for applications that are being launched directly (either from the command prompt, or from Windows explorer for instance).  Instead, that should be done through Windows itself using mechanisms like SRP, which apply equally to both managed and native applications.

In the v3.5 SP1 release, these observations (writing managed code to use on the network was harder than it needed to be, and it wasn’t even buying any extra security) led us to relax CAS policy for LocalIntranet applications slightly.   We enabled applications that were run directly from an intranet share (and any assemblies loaded from immediately next to that application) to be fully trusted by pretending that it had MyComputer zone evidence instead of LocalIntranet.

In the v4.0 release of the runtime, the CLR has taken that a step further.  By default, unhosted applications are not subject to managed security policy when run under v4.0.   Effectively, this means any managed application that you launch from the command prompt or by double clicking the .exe in Windows Explorer will run fully trusted, as will all of the assemblies that it loads (including assemblies that it loads from a location other than the the directory where the executable lives).

For applications run from the local machine, there really should be no observable change.  However, for applications that are shared out over a network, this means that everything should just work – just as if you had run the application from your computer while you were developing it.

One very important point about this change is that it specifically applies only to unhosted code.  In my next post, we’ll look at what v4.0 security policy means for CLR hosts.

Posted by shawnfa | 13 Comments
Filed under: , ,

.NET 4.0 Security

The first beta of the v4.0 .NET Framework is now available, and with it comes a lot of changes to the CLR's security system.  We've updated both the policy and enforcement portions of the runtime in a lot of ways that I'm pretty excited to finally see available.  Since there are a lot of security changes, I'll spend the next month or so taking a deeper look at each of them.  At a high level, the major areas that are seeing updates with the v4 CLR are: 

Like I did when we shipped the v2.0 CLR, I'll come back and update this post with links to the details about each of the features we added as I write more detailed blog posts about each of them.

Tomorrow, I'll start by looking at probably the most visible change of the group - the update to the CLR's security policy system.

Posted by shawnfa | 4 Comments
Filed under: , ,

Authenticated Symmetric Encryption in .NET

Over the last week, we've made a couple of updates to our Codeplex projects to add authenticated symmetric encryption to the managed cryptography surface area for the first time.  Since we've never supported authenticated symmetric algorithms in managed code before, I thought I'd run though some basics about what they are and how to use them.

For starters, in order to use the authenticated symmetric encryption classes, you'll need a few prerequisites:

  • Windows Vista SP 1, Windows Server 2008, or higher
  • .NET framework v3.5 SP 1 or higher
  • Security.Cryptography.dll 1.3 or higher (from http://codeplex.com/clrsecurity)

Authenticated symmetric cryptography differs from the symmetric cryptography that the .NET framework has traditionally supported in that it produces an authentication tag in addition to ciphertext when encrypting data.  This authentication tag can be used to verify that the ciphertext has not been tampered with between when it was encrypted and decrypted.

For example, imagine you encrypted a message using the AES class:

using (Aes aes = new AesCng())

{

    aes.Key = key;

    aes.IV = iv;

 

    using (MemoryStream ms = new MemoryStream())

    using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))

    {

        byte[] plaintext = Encoding.UTF8.GetBytes("Secret data to be encrypted.");

        cs.Write(plaintext, 0, plaintext.Length);

        cs.FlushFinalBlock();

 

        return ms.ToArray();

    }

}

While an attacker cannot read the data encrypted by this operation without knowing the encryption key, they can modify the ciphertext bytes themselves which will result in corruption of the decrypted message on the receiving end:

// The ciphertext is protected from being decrypted without knowledge of the key, however it

// is not protected from being tampered with:

ciphertext[5] = 0x21;

 

using (Aes aes = new AesCng())

{

    aes.Key = key;

    aes.IV = iv;

 

    using (MemoryStream ms = new MemoryStream())

    using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))

    {

        cs.Write(ciphertext, 0, ciphertext.Length);

        cs.FlushFinalBlock();

 

        byte[] decrypted = ms.ToArray();

        string message = Encoding.UTF8.GetString(decrypted);

        Console.WriteLine(message);

    }

}

Which produces output such as:

? ]\??e enc?ypted.

This can be solved by signing the ciphertext, and having the receiving party verify the signature before decrypting the secret message.

Authenticated symmetric algorithms solve this problem by creating an authentication tag which can be used to verify that the ciphertext has not been tampered with since it was generated.

In addition to verifying that the ciphertext has not been modified, the authenticated symmetric algorithms that we have in managed code also take additional authenticated data as an input.  This data is not included in the ciphertext itself - so when decrypting a message that was created with additional authenticated data, the output will not contain the authenticated data.  Instead, the authenticated data is only used in generating the authentication tag.  This means that much like the key and IV, both the encrypting and decrypting parties need to know what the additional authenticated data is otherwise the authentication tag will not verify.

Authenticated Symmetric Algorithm Type Hierarchy

This functionality is exposed in managed code via the AuthenticatedSymmetricAlgorithm base class.  Much like the SymmetricAlgorithm base class, AuthenticatedSymmetricAlgorithm is an abstract class for actual authenticated symmetric algorithms to derive from.

Currently, the only authenticated symmetric algorithm is an authenticated version of AES, which is represented by the AuthenticatedAes abstract base class.  Again, mirroring the symmetric algorithm type hierarchy, AuthenticatedAes is an abstract base class that concrete authenticated AES implementations derive from.  (Much like Aes serves as the base class for AesManaged, AesCryptoServiceProvider and AesCng).

The concrete implementation of AuthenticatedAesCng which is in Security.Cryptography.dll 1.3 is built on top of  CNG, and follows our traditional naming scheme: AuthenticatedAesCng.

Setting up an Authenticated AES Encryptor

The authentication tag is generated by an authenticated chaining algorithm, which is used in place of the standard chaining modes that AES can use (such as CBC or ECB).  Currently CNG supports two algorithms for generating an authentication tag with AES:

  1. Galois/Counter Mode - this is the default, and is represented by CngChainingMode.Gcm.  (http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf)
  2. Coutner with CBC-MAC - this is selected by using CngChainingMode.Ccm.  (http://www.ietf.org/rfc/rfc3610.txt)

Since neither of these chaining modes are supported by the standard CipherMode enumeration, AuthenticatedAesCng adds a new property called CngMode which allows you to specify a CngChainingMode rather than a standard CipherMode.  Trying to use the traditional Mode property when the CngChainingMode is set to one of these new values will result in an exception.

The IV property is used to setup what the two algorithm specifications above refer to as a nonce.  Unlike traditional AES, the IV size does not match the block size, but is instead specified by the chaining mode.  For instance, both GCM and CCM can work with an IV of 12 bytes.

AuthenticatedSymmetricAlgorithms also have an AuthenticatedData byte array property which is used to setup the additional authentication data being used in the tag generation.  This property is optional - leaving the value null means that the authentication tag is generated only from the plaintext.

The last interesting property on the encryption side is the TagSize property.  This property specifies the size (in bits) of the authentication tag to generate.  The LegalTagSizes property contains information about which sizes are valid for the current chaining mode (and the ValidTagSize method allows you to quickly test to see if a tag size is valid).

Once the AuthenticatedAesCng object is setup, we'll need to create an encryptor to do the actual encryption operation.  This can be done by calling the CreateAuthenticatedEncryptor method.  CreateAuthenticatedEncryptor returns an IAuthenticatdCryptoTransform rather than an ICryptoTransform since IAuthenticatedCryptoTransform allows us access to the authentication tag after the encryption is done.  The CreateEncryptor overloads also return IAuthenticatedCryptoTransforms, however they are typed as ICryptoTransform because they're defined on the SymmetricAlgorithm base type.  If you call one of the these methods, then you'll have to manually cast to IAuthenticatedCryptoTransform.

Putting this all together, code to encrypt and generate an authentication tag using AuthenticatedAesCng would look something like this:

using (AuthenticatedAesCng aes = new AuthenticatedAesCng())

{

    // Setup an authenticated chaining mode - The two current CNG options are

    // CngChainingMode.Gcm and CngChainingMode.Ccm.  This should be done before setting up

    // the other properties, since changing the chaining mode can update things such as the

    // valid and current tag sizes.

    aes.CngMode = CngChainingMode.Ccm;

 

    // Keys work the same as standard AES

    aes.Key = key;

 

    // The IV (called the nonce in many of the authenticated algorithm specs) is not sized for

    // the input block size. Instead its size depends upon the algorithm.  12 bytes works

    // for both GCM and CCM. Generate a random 12 byte nonce here.

    nonce = new byte[12];

    rng.GetBytes(nonce);

    aes.IV = nonce;

 

    // Authenticated data becomes part of the authentication tag that is generated during

    // encryption, however it is not part of the ciphertext.  That is, when decrypting the

    // ciphertext the authenticated data will not be produced.  However, if the

    // authenticated data does not match at encryption and decryption time, the

    // authentication tag will not validate.

    aes.AuthenticatedData = Encoding.UTF8.GetBytes("Additional authenticated data");

 

    // Perform the encryption - this works nearly the same as standard symmetric encryption,

    // however instead of using an ICryptoTransform we use an IAuthenticatedCryptoTrasform

    // which provides access to the authentication tag.

    using (MemoryStream ms = new MemoryStream())

    using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor())

    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))

    {

        // Encrypt the secret message

        byte[] plaintext = Encoding.UTF8.GetBytes("Secret data to be encrypted and authenticated.");

        cs.Write(plaintext, 0, plaintext.Length);

 

        // Finish the encryption and get the output authentication tag and ciphertext

        cs.FlushFinalBlock();

        tag = encryptor.GetTag();

        ciphertext = ms.ToArray();

    }

}

Notice how the tag is accessed by calling GetTag on the IAuthenticatedCryptoTransform after we've completed all encryption and flushed the final block.  If GetTag is called before this, it will throw an InvalidOperaitonException as AuthenticatedAesCng does not support generating partial tags for partially encrypted data.  Also, encryption will notably not set the Tag property of the AuthenticatedAesCng object which was used to create the encryptor.  (The tag is an output, not an input, and therefore does not get propagated back to the AuthenticatedAesCng object which acts like a crypto transform factory).

Setting up an Authenticated AES Decryptor

Setting up an authenticated AES object to do decryption is very similar to setting one up to do encryption.  The Key, IV, AuthenticationData, and CngMode all need to be setup to match the parameters in place when the ciphertext being decrypted was encrypted.  The only additional property that needs to be set is the Tag property.  Unsurprisingly, this should be set to be the output of the GetTag call on the encryptor.

We'll end up with decryption code along the lines of:

// To decrypt, we need to know the nonce, key, additional authenticated data, and

// authentication tag.

using (AuthenticatedAesCng aes = new AuthenticatedAesCng())

{

    // Chaining modes, keys, and IVs must match between encryption and decryption

    aes.CngMode = CngChainingMode.Ccm;

    aes.Key = key;

    aes.IV = nonce;

 

    // If the authenticated data does not match between encryption and decryption, then the

    // authentication tag will not match either, and the decryption operation will fail.

    aes.AuthenticatedData = Encoding.UTF8.GetBytes("Additional authenticated data");

 

    // The tag that was generated during encryption gets set here as input to the decryption

    // operation.  This is in contrast to the encryption code path which does not use the

    // Tag property (since it is an output from encryption).

    aes.Tag = tag;

 

    // Decryption works the same as standard symmetric encryption

    using (MemoryStream ms = new MemoryStream())

    using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))

    {

        cs.Write(ciphertext, 0, ciphertext.Length);

 

        // If the authentication tag does not match, we'll fail here with a

        // CryptographicException, and the ciphertext will not be decrypted.

        cs.FlushFinalBlock();

 

        byte[] plaintext = ms.ToArray();

        Console.WriteLine("Decrypted and authenticated message: {0}", Encoding.UTF8.GetString(plaintext));

    }

}

If the authentication tag generated while decrypting the ciphertext (taking into account any optional authenticated data provided), then an exception will be thrown when decryption is completed.  The decryptor will also not produce any plaintext until the authentication tag is verified - this way partial plaintext cannoot be used if the authentication tag does not match.

Now that we're using AuthenticatedAesCng to do our encryption, the scenario where someone tampers the ciphertext no longer works.  While we won't be able to access the corrupted plaintext anymore, we also will be unable to mistake it for valid plaintext.  If the authentication tag does not match while decrypting (most commonly because the ciphertext was tampered with or the authenticated data was not correct), the following exception is thrown:

Unhandled Exception: System.Security.Cryptography.CryptographicException: The computed authentication tag did not match the input authentication tag.

   at Security.Cryptography.BCryptNative.SymmetricDecrypt(SafeBCryptKeyHandle key, Byte[] input, Byte[] chainData, BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO& authenticationInfo)
   at Security.Cryptography.BCryptAuthenticatedSymmetricCryptoTransform.CngTransform(Byte[] input, Int32 inputOffset, Int32 inputCount)
   at Security.Cryptography.BCryptAuthenticatedSymmetricCryptoTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at System.Security.Cryptography.CryptoStream.FlushFinalBlock()

Security.Cryptography.Debug Support

The Security.Cryptography.Debug library has also been updated on the Codeplex in order to support the same type of debugging of AuthenicatedSymmetricAlgorithm objects that was already supported for SymmetricAlgorithm objects.  This support is enabled in the v1.1 release and higher of Security.Cryptography.Debug.dll - but since it requires a dependency on the Security.Cryptography.dll library, it is not enabled in the FxOnly builds.  Instead, you'll need to download the full binary package or build the sources manually to get the AuthenticatedSymmetricAlgorithm debugging support.

Posted by shawnfa | 3 Comments
Filed under: ,

MD5 on Silverlight

Reid Borsuk, an SDE/T on the CLR security team, has released a fully transparent implementation of the MD5 hash algorithm to the MSDN Code Gallery.  Since the code is entirely transparent, it can be used as part of a Silverlight application that needs to compute MD5 hashes in order to interop with existing code or file formats that requires MD5.

He's also released an MD5Managed type to wrap around his implementation, in case you want to plug the algorithm into the standard .NET hash object model.

Posted by shawnfa | 1 Comments

CryptoConfig

The crypto config schema has been a bit of a hot topic around here lately, specifically around how to modify the CLR's machine.config to get custom crypto types registered with CryptoConfig.

Let's take a quick look at what CryptoConfig is first, and then we'll see how to customize its behavior.  CryptoConfig is a type in mscorlib which allows cryptography classes to be created from a string rather than using a hard coded type.  For instance, you can say:

HashAlgorithm hashAlgorithm = CryptoConfig.CreateFromName("SHA256Managed") as HashAlgorithm;

to create instances of crypto types. This means that rather than having to hard code algorithms and implementations into your assembly itself, you can accept the name of the algorithm as a configuration parameter to achieve some measure of crypto agility.  CryptoConfig is also the underlying mechanism that allows the algorithm factory methods to work.  For instance, the above snippet is more commonly written as:

HashAlgorithm hashAlgorithm = HashAlgorithm.Create("SHA256Managed");

CryptoConfig comes built in with names of algorithms that ship with the .NET Framework (with the exception of the new algorithms introduced in .NET 3.5 due to red bits / green bits restrictions).  You can also extend the names that CryptoConfig understands if you have your own algorithms that you would like to be createable by name.  In fact, you can even do this to get the .NET 3.5 algorithms registered.

The customizable algorithm name mappings are setup in the machine.config file in the config subdirectory of the CLR installation directory.  For instance, for the 32 bit .NET 2.0, 3.0, and 3.5 releases you would register your types in the %WINDIR%\Microsoft.NET\Framework\v2.0.50727\config\machine.config file.  (For the 64 bit versions, you would also need to modify the equivalent file in Framework64).

CryptoConfig looks for information in the configuration/mscorlib/cryptographySettings element of machine.config. If there are multiple mscorlib sections, then crypto config prefers one with a version attribute that matches the current runtime -- however, in general there is only one mscorlib element.

<configuration>

    <mscorlib>

        <cryptographySettings>

            <cryptoNameMapping>               

                <!-- name mappings -->

            </cryptoNameMapping>

            <oidMap>

                <!-- OID mappings -->

            </oidMap>

        </cryptographySettings>

    </mscorlib>

</configuration>

Name mappings are created in a nameMappings element under cryptographySettings.  In order to setup a name mapping, two steps are required:

  1. Map the implementation type to an alias by registering it as a crypto class
  2. Map the alias to the name that you wish to use in CryptoConfig to create an instance of the class.

For example, imagine that you want to register the SHA256CryptoServiceProvider type that shipped in .NET 3.5 to be able to be created with the strings "SHA256", "SHA256CryptoServiceProvider", and "System.Security.Cryptography.SHA256ServiceProvider".  The first step is to register SHA256CryptoServiceProvider as a crypto class.  We can do this by creating a cryptoClasses node within the cryptoNameMapping element:

<cryptoClasses>

    <cryptoClass

        SHA256CSP="System.Security.Cryptography.SHA256CryptoServiceProvider, System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

</cryptoClasses>

This creates an alias of SHA256CSP that refers to the SHA256CryptoServiceProvier type in System.Core.dll.  Note that the assemblies used in CryptoConfig must reside in the GAC; in this case System.Core.dll is in the GAC so registering SHA256CryptoServiceProvider is valid.

Now that we have created an alias we need to setup some names to create it with at runtime.  These names are created using nameEntry elements in the cryptoNameMapping element:

<nameEntry

    name="SHA256"

    class="SHA256CSP" />

<nameEntry

    name="SHA256CryptoServiceProvider"

    class="SHA256CSP" />

<nameEntry

    name="System.Security.Cryptography.SHA256CryptoServiceProvider"

    class="SHA256CSP" />

Each nameEntry element maps a string which CryptoConfig will accept to the alias for the type that it will create.  Here, we've setup entries that allow CryptoConfig to create a SHA256CryptoServiceProvier object via the names "SHA256", "SHA256CryptoServiceProvider", and "System.Security.Cryptography.SHA256CryptoServiceProvider".

If you're paying close attention, you'll notice that I mapped SHA256 to the .NET 3.5 SHA256CryptoServiceProvider class, even though the CLR already has a built in mapping for SHA256 to the SHA256Managed class.  In the case of a collision like this, machine.config entries take precedence over the built in mappings so these entries have the effect of changing the result of HashAlgorithm.Create("SHA256") from being a SHA256Managed object to being a SHA256CryptoServiceProvider object.

The final XML we ended up with for this example looks like this:

<configuration>

    <!-- ... other configuration data ... -->

    <mscorlib>

        <!-- ... other configuration data ... -->

        <cryptographySettings>

            <cryptoNameMapping>

                <cryptoClasses>

                    <cryptoClass

                        SHA256CSP="System.Security.Cryptography.SHA256CryptoServiceProvider, System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

                </cryptoClasses>

                    <nameEntry

                        name="SHA256"

                        class="SHA256CSP" />

                    <nameEntry

                        name="SHA256CryptoServiceProvider"

                        class="SHA256CSP" />

                    <nameEntry

                        name="System.Security.Cryptography.SHA256CryptoServiceProvider"

                        class="SHA256CSP" />

            </cryptoNameMapping>

        </cryptographySettings>

    </mscorlib>

</configuration>

A couple of other small crypto config notes:

Above I mentioned that there is the ability to setup OID mappings - this allows you to add entries to the results returned from the CryptoConfig.MapNameToOid API.  These entries go in the oidMap element and are simple name -> OID pairs.  Like name map entries above, machine.config values take precedence over built-in values:

<oidMap>

    <oidEntry

        OID="2.16.840.1.101.3.4.2.1"

        name="SHA256" />

</oidMap>

Generally this is much less useful than the name mappings, since it really only allows you to access your custom OIDs via MapNameToOid -- however it's there if you do want to add custom name->OID pairs.

A final note is that although CryptoConfig itself doesn't have an API to modify the mappings at runtime, it is sometimes a lot more convenient to programmatically add crypto name mappings for your application at runtime than to worry about getting all the machine.config XML correctly added at installation time.  This can be done with the CryptoConfig2 class from the Security.Cryptography library on CodePlex.

CryptoConfig2 already has mappings for the .NET 3.5 types, but for the sake of an example the registration from the XML above could be done via code such as:

CryptoConfig2.AddAlgorithm(typeof(SHA256CryptoServiceProvider),

                           "SHA256",

                           "SHA256CryptoServiceProvider",

                           "System.Security.Cryptography.SHA256CryptoServiceProvider");

Since CryptoConfig2 does not modify the built-in CryptoConfig mappings, these aliases would be used like this:

HashAlgorithm hashAlgorithm = CryptoConfig2.CreateFromName("SHA256") as HashAlgorithm;

instead of going through the built in CryptoConfig or Create methods.

Posted by shawnfa | 1 Comments
Filed under: ,

Using RSACryptoServiceProvider for RSA-SHA256 signatures

Earlier this month, we released .NET 3.5 SP 1.  One of the new features available in this update is that RSACryptoServiceProvider has gained the ability to create and verify RSA-SHA256 signatures.

Since RSACryptoServiceProvider relies on the underlying CAPI APIs to do its work, this feature will only be enabled on versions of Windows which support SHA-256 algorithms in CAPI.  At this point, that translates to Windows Server 2003 and higher.

The code to create and verify a signature is basically the same as it was for doing RSA-SHA1:

byte[] data = new byte[] { 0, 1, 2, 3, 4, 5 };

using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())

{

    byte[] signature = rsa.SignData(data, "SHA256");

 

    if (rsa.VerifyData(data, "SHA256", signature))

    {

        Console.WriteLine("RSA-SHA256 signature verified");

    }

    else

    {

        Console.WriteLine("RSA-SHA256 signature failed to verify");

    }

}

The second parameter should be either the string "SHA256", the type of the SHA256Managed object, or an instance of a SHA256Managed object.

Note that this means, somewhat counter-intuitively, that passing either the type of or an instance of the SHA256CryptoServiceProvider object will not work.  If you do use the SHA256CryptoServiceProvider type, you'll end up with an error like this:

Unhandled Exception: System.ArgumentException: Value was invalid.

   at System.Security.Cryptography.Utils.ObjToOidValue(Object hashAlg)

   at System.Security.Cryptography.RSACryptoServiceProvider.SignData(Byte[] buffer, Object halg)

The reason for this is the same reason that CryptoConfig does not understand SHA256CryptoServiceProvider - it was added as part of the green bits in .NET 3.5, and due to layering restrictions the red bits (such as mscorlib.dll where RSACryptoServiceProvider lives) does not know about its existence.

Also note that this functionality was added only to the RSACryptoServiceProvider type, so upstack functionality such as XML digital signatures are not yet enabled for RSA-SHA256 digital signatures.  However, this does provide the base building block for those upstack crypto technologies, so that they can begin adding support in the future.

Posted by shawnfa | 4 Comments
Filed under: ,

CLR Security Team CodePlex Site

The CLR Security Team just launched our CodePlex site: http://www.codeplex.com/clrsecurity.  Currently, it contains two assemblies that provide additional functionality to the security APIs shipped in v3.5 of the .NET Framework.

We'd love your feedback on the currently offered libraries, and also welcome ideas for other libraries you'd like to see on our CodePlex site. 

From the description page on the site, the two current libraries are:

Security.Cryptography.dll

Security.Cryptography.dll provides a new set of algorithm implementations to augment the built in .NET framework supported algorithms. It also provides some APIs to extend the existing framework cryptography APIs. Within this project you will find:

  • A CNG implementation of the AES, RSA, and TripleDES encryption algorithms
  • A CNG implementation of a random number generator
  • A class that allows dynamically creating algorithms both from this library as well as all of the algorithms that ship with .NET 3.5
  • An enumerator over all of the installed CNG providers on the current machine
  • Extension methods that allow access to all of the keys installed in a CNG provider, as well as all of the algorithms the provider supports

Security.Cryptography.Debug.dll

Have you ever run into an indecipherable cryptographic exception complaining about "Padding is invalid and cannot be removed" when using the .NET Framework's symmetric algorithms? Since nearly all bugs relating to symmetric algorithms tend to result in this same exception, it can be incredibly difficult to track down exactly what went wrong to cause the exception. Security.Cryptography.Debug.dll is a tool that can be used in these circumstances in order to help you figure out the root cause of your cryptographic exception.

Posted by shawnfa | 1 Comments
More Posts Next page »
 
Page view tracker