StrongNameIdentityPermission

ok bear with me here as I am not exactly sure if I am using this correctly:

I am fooling around with StrongNameIdentityPermission

I have two assemblies (both assigned the same .snk file in there AssemblyInfo.cs)

Assembly                Namespace
MyApp.Utility.dll       MyApp.Utility
MyApp.exe               MyApp

MyApp.exe references MyApp.Utility.dll

I have a class MyApp.Utility.Permission with a method prototyped:


public static bool Authorize()
 


In my exe I have a main form with a button. . . the click event handler is defined as


private void button1_Click(object sender, System.EventArgs e)
{
   if
(MyApp.Utilities.Permission.Authorize())
      MessageBox.Show("Permission Granted");
   else
      MessageBox.Show("Permission Denied");
}

 

I have an exe with a strong name. I ran secutil -s MyApp.exe which returned:
===================
Public Key =
{ 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0,
0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 151, 42, 61,
193, 163, 198, 44, 135, 25, 226, 210, 17, 82, 161, 67, 69, 73, 117,
15, 166, 211, 81, 225, 148, 243, 27, 172, 79, 239, 46, 44, 176,
134, 70, 206, 35, 85, 231, 74, 159, 28, 208, 250, 29, 75, 155, 227,
249, 30, 244, 191, 84, 174, 145, 81, 99, 124, 48, 51, 114, 153, 202,
158, 253, 255, 50, 174, 136, 82, 225, 237, 246, 237, 197, 207, 104,
17, 79, 143, 52, 42, 58, 98, 43, 158, 10, 144, 223, 205, 119, 187,
142, 40, 166, 85, 68, 61, 105, 231, 159, 102, 210, 147, 105, 129,
141, 31, 70, 86, 167, 55, 228, 200, 202, 170, 246, 205, 187, 119,
67, 75, 63, 236, 119, 57, 6, 117, 181 }
Name =
MyApp
Version =
1.0.2164.2229
Success
===================

I then went into MyApp.Utility.Permission and redefined it as:


public class Permission
{
  private Permission(){}
 
  public static bool Authorize()
  {
    try
    {
      byte[] key =
          {
            0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 
            0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 
            1, 0, 1, 0, 151, 42, 61, 193, 163, 198, 44, 
            135, 25, 226, 210, 17, 82, 161, 67, 69, 73, 
            117, 15, 166, 211, 81, 225, 148, 243, 27, 
            172, 79, 239, 46, 44, 176, 134, 70, 206, 35, 
            85, 231, 74, 159, 28, 208, 250, 29, 75, 155, 
            227, 249, 30, 244, 191, 84, 174, 145, 81, 99, 
            124, 48, 51, 114, 153, 202, 158, 253, 255, 
            50, 174, 136, 82, 225, 237, 246, 237, 197, 207, 
            104, 17, 79, 143, 52, 42, 58, 98, 43, 158, 10, 
            144, 223, 205, 119, 187, 142, 40, 166, 85, 
            68, 61, 105, 231, 159, 102, 210, 147, 105, 
            129, 141, 31, 70, 86, 167, 55, 228, 200, 202,
            170, 246, 205, 187, 119, 67, 75, 63, 236, 119,
             57, 6, 117, 181};

      StrongNamePublicKeyBlob blob = 
               new StrongNameIdentityPermission(key);

      /* Not worried about name and version right now. . .  */
      StrongNameIdentityPermission sniPerm = 
            new StrongNameIdentityPermission(blob, null,null);

      sniPerm.Demand();
      return true;
    }
    catch(Exception e)
    {
      System.Diagnostics.Debug.WriteLine(e.Message);
      return false;
    }
  }
}

 


when I run MyApp.exe Authorize goes to the catch block and writes this to the debug console:

Request for the permission of type System.Security.Permissions.StrongNameIdentityPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.

What am I missing

the key is supposed to be the public key of the calling exe, correct




Answer this question

StrongNameIdentityPermission

  • David McAuley

    nope. . .thought about this . . nothing prevents someone from reflecting my assembly's evidence and passing that.

  • Kjell Ahlstrom

    It's also quite possible for highly privileged code to spoof evidence passed to the CLR, so reading evidence in other manners won't help either.  There really is no guaranteed solution here if you need to protect against highly privileged malicious callers.  The best you can do is protected against low privilege callers and (in v. 1.x only) high privilege "honest" callers.
  • Mike2006

    I found Nicole's comments very helpful in the quest to keep unauthorized code from calling my assemblies.

    I have seen msdn sample code (http://msdn2.microsoft.com/en-US/library/system.security.permissions.strongnameidentitypermission(VS.80).aspx) that shows how to programmatically extract the strong name from the calling assembly and compare it to my strong name. I prefer to use authenticode signature over strong names to avoid all the versioning headaches. Does anyone know how to detect the authenticode signature of a calling assembly

    Thanks



  • Tick Tock

    Thanks Nicole. After more research I'm discovering the flaws with authenticode in a Remoting architecture. I've been reading about problems with having to hit the CA to check for a revoked certificate: Poor server performance, or security hacks to bypass the CA check. And it implies constant Internet access, which I can't guarantee at all my customer installations. With that in mind I'm putting my attention back on strong names to verify the caller in a Remoting environment.

    Has anyone looked into the approach taken by N.T.Gopalakrishnan His article at http://www.dotnetspider.com/kb/Article885.aspx talks about using a Remoting channel sink. It looks solid to me, but if anyone has critiqued it I'd love to hear what you think.

    Thanks,

    John



  • Helena Kotas

    As with any other similar solution, there's nothing stopping a malicious client from spoofing the call stack data in Mr. Gopalakrishnan's article. There really is no solid way to ensure that your server code is being called by the expected client application.

    Rather than trying to enforce the unenforceable, you would be better off assuming that your server is being called by a malicious client and treating all client-sourced data accordingly. In most situations, this will mean making only two changes:

    1. Do not trust self-declared user identities from the client.
    2. Validate all data on the server, even if validation is also carried out on the client.

  • Rob Zare

    A Demand call verifies every frame on the call stack.  There is .NET Framework code on the call stack at the time of your demand (Windows Forms code for firing the button's click event), and the Framework assemblies are signed with a different strong name key, so the demand fails.  This is why one usually sees a LinkDemand used for identity permissions instead of a full Demand.  If you want to crawl the entire stack, you'll need to accomodate the possibility of other keys.  See http://blogs.msdn.com/eugene_bobukh/archive/2004/03/10/87603.aspx for a sample of this sort of thing.

    Also, you may want to keep in mind that even in v. 1.x of the Framework, StrongNameIdentityPermission verifications are quite trivial to bypass by
    code with certain "high privilege" CAS permissions.  In addition, all code
    running with unrestricted CAS permissions (aka "full trust") automatically
    passes demands for any identity permission in v. 2.0.  Given this, you might
    want to consider using some alternate mechanism (e.g.: licensing) for
    limiting callers.


  • Brandon H. Campbell

    You can grab the authenticode signing certificate System.Security.Policy.Publisher evidence from the assembly's evidence. If the assembly signature is not valid, the evidence should not be populated with a Publisher entry.
  • Jeevanantham

    this stuff is all new to me. . .

    question:

    Isn't this adequate to determine that both assemblies MyApp.exe and MyApp.Utilities.dll were signed with the same snk file:



    /* assembly MyApp.Utilities.dll */
    public class Permission
    {
     
     private static Permission(){}

     private static StrongName GetStrongName(Evidence evid)
     {
      foreach(object o in evid)
      if (o is StrongName)
       return o as StrongName;
      return null;
     }

     public static bool Authorize(Evidence evid)
     {
      Assembly asm = typeof(Permission).Assembly;
      StrongName snThis = GetStrongName(asm.Evidence);
      if  (snThis == null) return true;
      if  (evid == null) return false;
      StrongName snCaller = GetStrongName(evid);
      if (snCaller == null) return false;
      if (snThis.PublicKey.ToString() == snCaller.PublicKey.ToString()) return true;
      return false;
        }
    }

     




    usage:


    /*assembly MyApp.exe */
    public void DoSecureProc()
    {
       if !MyApp.Utilities.Permissions.Authorize(this.GetType().Assembly.Evidence))
          throw new System.Security.SecurityException("Unauthorized Execution"); 
       /*do process here */

    }
     



  • Suman Ray

     Nicole Calinoiu wrote:

    Also, you may want to keep in mind that even in v. 1.x of the Framework, StrongNameIdentityPermission verifications are quite trivial to bypass by
    code with certain "high privilege" CAS permissions.  In addition, all code
    running with unrestricted CAS permissions (aka "full trust") automatically
    passes demands for any identity permission in v. 2.0.  Given this, you might
    want to consider using some alternate mechanism (e.g.: licensing) for
    limiting callers.


    thanks for the info!

    I am assuming that this will be adequate as we wouldn't be using it to protect any proprietary info. We are looking at a giving our customers the ability to protect data. It would be up to them to prevent their users from executing 'privileged' code, correct

  • StrongNameIdentityPermission