We are working on creating an installation package for a WCF-based web service. The service uses message-level encryption via an installed certificate. I am trying to come up with an automated way to both install the certificate and set its permissions.
Currently, we are manually installing the certificate via the MMC snap-in. After it is installed, we need to find the file containing the installed certificate and modify the permissions so that the Network Service account can access it. The only way I know to find the file is to open the "...\Microsoft\Crypto\RSA\MachineKeys" folder (exact path differs based on platform) and identify the file with the most recent modified date.
I'm thinking we'll use WIX to create the installation package. WIX has a specific feature for installing a certificate, but I assume permissions will still be an issue. Is there some utility or API or other means to get the physical path for an installed certificate identified by the subject name (or similar).
Of course, maybe there's a more direct solution to this problem.
Thanks for any help with this issue.
Source: Least Privilege
There is no clean way to do that in managed code. The general procedure is:
- Select a certificate
- Create an RSACryptoServiceProvider object from the certificate's PrivateKey property
- Retrieve the UniqueKeyContainerName property.
- Search for this file name in the various locations where keys are stored. Thats under ApplicationData for user keys and CommonApplicationData for machine keys
If you want to do this in a custom action, I recommend you do this in C++. (Managed Custom Actions are most of the time not a good idea.)
If you only want to set ACLs, there are two tools that can do that for you:
- WinHttpCertCfg.exe
- The certificates tool included in WSE3
See the link for the details, hope this helps!
Does the certificate need to be installed? Could you reference it from a PFX file or similar instead, negating any need for installation?
A certificate itself doesn't have permissions. It can be in either a user's certificate store, such as the MY, CA or ROOT stores. Or it can be in the computer's version of those stores. It sounds like you are also installing a private key along with the certificate. To make a private key accessible to a service, it should be installed to the computer's key store. If you doing the import manually via something like CryptImportKey, you should specify CRYPT_MACHINE_KEYSET when the key container is acquired with CryptAcquireContext.