3

I am trying to automate deployment of certificates, including managing permissions on the private key. Using this question, I have cobbled together some code that should update permissions for a certificate:

public static SetPermissionsResult SetPermissions(X509Certificate2 certificate, string userName)
{
    var account = new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null);

    using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
    {
        store.Open(OpenFlags.MaxAllowed);

        var newCertificate = store.Certificates.Find(X509FindType.FindBySerialNumber, certificate.SerialNumber, false)[0];

        var rsa = newCertificate.PrivateKey as RSACryptoServiceProvider;
        if (rsa == null)
        {
            return SetPermissionsResult.Failure;
        }

        rsa.PersistKeyInCsp = true;

        var cspParams = new CspParameters(
            rsa.CspKeyContainerInfo.ProviderType,
            rsa.CspKeyContainerInfo.ProviderName,
            rsa.CspKeyContainerInfo.KeyContainerName)
                            {
                                Flags =
                                    CspProviderFlags.UseExistingKey
                                    | CspProviderFlags.UseMachineKeyStore,
                                CryptoKeySecurity =
                                    rsa.CspKeyContainerInfo.CryptoKeySecurity,
                                KeyNumber = (int)rsa.CspKeyContainerInfo.KeyNumber/*,
                                KeyPassword = password*/
                            };

        cspParams.CryptoKeySecurity.AddAccessRule(
            new CryptoKeyAccessRule(account, CryptoKeyRights.GenericRead, AccessControlType.Allow));

        using (var rsa2 = new RSACryptoServiceProvider(cspParams))
        {
        }

        return SetPermissionsResult.Success;
    }
}

On the line that reads using (var rsa2 = new RSACryptoServiceProvider(cspParams)) (where the new crypto provider is instantiated to persist the new access rule), I get a CryptographicException "Keyset does not exist".

I know from experience that this generally means that the current security context does not have permissions to access the primary key. To troubleshoot this possibility, I have done the following:

  1. Figure out what the current user is with System.Security.Principal.WindowsIdentity.GetCurrent() in the Immediate window
  2. Ensure that that user has Full control permission in the MMC snap-in for certificates (and double-checked that I'm looking at the right store for it)
  3. Granted Full control to the Everyone user.
  4. Tried creating the CspParameters object with and without the KeyPassword (you can see it commented there).

I am out of ideas. The certificate is a bogus self-signed test cert, so it's not a matter of other certs in the chain missing permissions. Any help would be appreciated.

UPDATE:

I've been able to get this code to execute by modifying some of the flags for the installation of the certificate that precedes this step. Now, the code executes, apparently successfully, but to no visible effect I can see in the MMC.

Chris B. Behrens
  • 6,384
  • 8
  • 41
  • 67

1 Answers1

3

I resolved this issue, more or less. The code for managing permissions listed above is sound. What was problematic was the code for instiating the certificate before adding it. The common sense way to that looks like this:

var certificate = new X509Certificate2(bytes, password);

The problem with this is that it doesn't cause the private key to be persisted in the store, which is what the permissions code relies on (duh). To cause this to happen, you need to instantiate the certificate to be added to the store like this:

var certificate = new X509Certificate2(bytes, "password123", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

And add it like this:

using (var store = new X509Store(storeName, StoreLocation.LocalMachine))
{
       store.Open(OpenFlags.MaxAllowed);

       store.Add(certificate);
}

FINAL POINT: the MMC snap-in is dicey about displaying the updated permissions, i.e., it may not display the new permissions even though they actually have changed. I reached a point where I had everything working perfectly, but didn't realize it because the MMC was showing me different. Closing the MMC and reopening forces a refresh if you're doubting what you're seeing.

Chris B. Behrens
  • 6,384
  • 8
  • 41
  • 67