FukingLost
FukingLost

Reputation: 13

Grant user permission to the private key

installing my WCF service I also install certificate with private key. Since I will be running service as a different user, that user needs access to the private key. I extensively read other stackoverflow questions and they all suggest permission on private key file in file system needs to adjusted. I do this by,

        private static void AddUserPermissions(X509Certificate2 certificate, NTAccount user, StoreLocation storeLocation)
        {
            RSACryptoServiceProvider rsaProvider = (RSACryptoServiceProvider)certificate.PrivateKey;

            // Find file 
            string keyPath = FindKeyLocation(rsaProvider.CspKeyContainerInfo.UniqueKeyContainerName, storeLocation);
            FileInfo keyFileInfo = new FileInfo(keyPath);

            // Create new FileSecurity
            FileSecurity keyFileSecurity = keyFileInfo.GetAccessControl();
            keyFileSecurity.AddAccessRule(new FileSystemAccessRule(user, FileSystemRights.Read, AccessControlType.Allow));

            // Apply file security to the file
            keyFileInfo.SetAccessControl(keyFileSecurity);
        }

When I run my program and inspect the private key file I can see, for example "Network Service" has been added to the permissions list.

Great, that's working, but when WCF tries to use private key, it cannot access it.

Looking at certlm, certificate -> All Tasks -> Manage Private Keys.. I can see that my user is not on the list. Adding my user through GUI solves the issue, but I need to do it in code!!

Upvotes: 1

Views: 1956

Answers (2)

Alex Lein
Alex Lein

Reputation: 503

Anyone who gets this far looking for a solution for ECDSA certificate keys, I found a way!

string keyUniqueName = (certificate.GetECDsaPrivateKey() as ECDsaCng)?.Key.UniqueName
                ?? (certificate.GetRSAPrivateKey() as RSACng)?.Key.UniqueName
                ?? throw new NotSupportedException("No ECDSA or RSA key found");

In the example code from the question, the FindKeyLocation gets passed rsaProvider.CspKeyContainerInfo.UniqueKeyContainerName, instead you would pass keyUniqueName as taken from my example.

One more good note, the accepted answer from Daniel Fisher lennybacon correctly documents where keys are stored based on where they were generated/installed. But you should use Environment.SpecialFolder.CommonApplicationData or Environment.SpecialFolder.ApplicationData for key file paths.

Also, I found my keys in c:\ProgramData\Microsoft\Crypto\, not c:\ProgramData\Application Data\Microsoft\Crypto\.

Upvotes: 1

Daniel Fisher  lennybacon
Daniel Fisher lennybacon

Reputation: 4194

Crypto Service Provider (Microsoft RSA SChannel Cryptographic Provider)

The keys are located in C:\ProgramData\Application Data\Microsoft\Crypto\RSA\MachineKeys and setting a normal file permission here is reflected in certlm.msc.

CSP

Crypto Next Generation (Microsoft Key Storage Provider)

The keys are located in C:\ProgramData\Application Data\Microsoft\Crypto\Keys and setting a normal file permission here is reflected in certlm.msc.

CNG

Summary

Ensure you modify the permissions on the right file in the right location.

Upvotes: 1

Related Questions