0

I have a small application as a 'certificate manager' to a larger program, so that users won't have to manually install and configure certificates.

It's fairly simple - it has some certificates as Embedded Resources, which it loads into the appropriate stores, then sets appropriately configured permissions.

This appears to work correctly while the program is running. Using MMC, I can see that the certificate is installed. If I Manage Private Keys, it has a new permission added correctly. However, as soon as I close the certificate manager, the permissions break. The certificate is still installed, but hitting Manage Private Keys pops up an error similar to "Key does not exist."

Additionally, if the program is run a second time, the permissions will 'stick' correctly after the program exits.

Here's code which the program uses to verify that the permissions were added. This method returns 'true' every time, even when the permissions break afterwards.

    private bool GetSecurityStatus(X509Certificate2 cert, X509Store store)
    {
        store.Open(OpenFlags.ReadOnly);

        //add Authenticated Users to private cert
        RSACryptoServiceProvider privKeyRSA = cert.PrivateKey as RSACryptoServiceProvider;
        string keyFilePath = FindKeyLocation(privKeyRSA.CspKeyContainerInfo.UniqueKeyContainerName);
        FileInfo privateKeyFileInfo = new FileInfo(keyFilePath + "\\" + privKeyRSA.CspKeyContainerInfo.UniqueKeyContainerName);
        FileSecurity privateKeyFileSecurity = privateKeyFileInfo.GetAccessControl();

        AuthorizationRuleCollection rules = privateKeyFileSecurity.GetAccessRules(true, true, typeof(NTAccount));
        foreach (FileSystemAccessRule fsar in rules)
        {
            if(fsar.IdentityReference.Value.Contains("Authenticated Users") && fsar.AccessControlType == AccessControlType.Allow && fsar.FileSystemRights == FileSystemRights.FullControl){
                store.Close();return true;
            }
        }
        //Close Private Cert store
        store.Close();
        return false;
    }

The FindKeyLocation returns the appdata\Microsoft\Crypto\RSA\ path of the private key.

I'm thinking it has to do somehow with the exiting of the program altering the private key file itself, but I'm unsure why it would then work the second time.

Skyl3lazer
  • 368
  • 2
  • 10
  • You don't seem to be using the store at all (except to open and close it) meaning you're checking up on the permissions of the private key associated with `cert`, but not necessarily the representation of `cert` in the cert store. – bartonjs Apr 17 '17 at 14:44
  • @bartonjs the given code was just to demonstrate that the permissions themselves had been found. – Skyl3lazer Apr 17 '17 at 15:00
  • 1
    Yes, but the two different cert instances can disagree on what private key they use if they were loaded independently from a PFX. So if your detection code is changed to read the store very permissions you may find that there's a different problem underneath. – bartonjs Apr 17 '17 at 15:02
  • @bartonjs I get you - there's actually code in a different area which gets the certificate directly from the store, it just wasn't included in this snippet. Thanks! – Skyl3lazer Apr 17 '17 at 15:04

1 Answers1

1

I believe I've found a solution to my issue, based on the respones here:

Import certificate with private key programmatically

and from MSDN here

https://support.microsoft.com/en-us/help/950090/installing-a-pfx-file-using-x509certificate-from-a-standard-.net-application

I had to pass two flags within the certificate's parameters, instead of just MachineKey

X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
Community
  • 1
  • 1
Skyl3lazer
  • 368
  • 2
  • 10