Search code examples
c#.netcryptographyrsacryptoserviceproviderdpapi

Attempt to set permissions on a KeyContainer in C# is having no effect


I'm using the following code in an attempt to programatically allow the NetworkService account to have access to a key:

var RSA = new RSACryptoServiceProvider(
   new CspParameters() { 
     KeyContainerName = "MyEncryptionKey", 
     Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore 
});

RSA.CspKeyContainerInfo.CryptoKeySecurity.AddAccessRule(
  new System.Security.AccessControl.CryptoKeyAccessRule(
    new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null),
    CryptoKeyRights.GenericAll,
    AccessControlType.Allow
  )
);

This code runs without error, but has no effect on the key container's permissions.

However, using the commandline tool aspnet_regiis to do the same thing, works perfectly:

aspnet_regiis -pa "MyEncryptionKey" "NetworkService"

I'm running with full admin rights - if I don't run with those rights, then an exception is thrown. I'm also running as the user that initially created the key.

The key container always has the following access rules:

S-1-5-18         -> LocalSystem
S-1-5-32-544     -> Administrators
S-1-5-5-0-135377 -> MyUser

With aspnet_regiis, the SID, S-1-5-20 gets added to this list. I can't affect it from code.

I've tried creating the security identifier from the sid in string format, as well as using SetAccessRule instead of AddAccessRule.

Any ideas how to actually affect this ACL list from code?


Solution

  • You do not appear to be calling Persist. The changes you make to the CryptoKeySecurity do not actually get saved immediately. You need to use one of the Persist(...) methods to actually save the changes.

    NativeObjectSecurity.Persist Method (String, AccessControlSections)

    It seems these API's follow a rather convoluted approach to modification. You need to create a CspParameters first, apply the necessary changes, then construct the provider from those parameters. Construction invokes an update on the container.

    var params = new CspParameters
    {
         KeyContainerName = "MyEncryptionKey", 
         Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore    
    };
    
    params.CryptoKeySecurity.AddAccessRule(
      new System.Security.AccessControl.CryptoKeyAccessRule(
        new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null),
        CryptoKeyRights.GenericAll,
        AccessControlType.Allow
      )
    );
    
    var RSA = new RSACryptoServiceProvider(params);