I have a WCF service hosted on IIS. The service is running in an app pool using Network Service account and uses a server certificate.
The service could be browsed without any problems until I recently installed a new certificate in my LocalMachine in the store “Personal Certificates”. Now while trying use the new one I get a Cryptographic Exception as below.
Exception type: CryptographicException
Exception message: Keyset does not exist
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize,
The goal is to troubleshoot the CryptographicException.
It is very common that the certificate may get imported successfully on a system but we still face the above error. In such scenarios there are some few simple steps to troubleshoot the issue.
Locate the certificate that your application is trying to use in the MMC console (Local Machine). Make sure that there is a Private Key associated with the certificate.
- · Double-click the certificate.
- · In the Certificate dialog box, click the Details tab.
- · Scroll through the list of fields and click Thumbprint.
- · Copy the Thumbprint.
Next we need to use the tool “FindPrivateKey.exe”.
This is a very handy tool that allows us to locate the physical container for the key using its Thumbprint. It can be download from the internet.
To download the tool, you need to install the complete WCF_WF samples from the link - http://www.microsoft.com/en-us/download/confirmation.aspx?id=21459.
Once installed, browse to the folder - <installed fodler>\WCF\Tools\FindPrivateKey\CS\ and open the .sln file. Build the project to generate the .exe in the bin folder.
Now, open an administrator command prompt and move to the directory where the “FindPrivateKey.exe” is present and then run the below command.
FindPrivateKey.exe My LocalMachine –t “<thumbprint>” –a
>> findprivatekey.exe My LocalMachine -t "f3 f7 7f a4 a1 29 2f 19 66 f4 a1 95
ce 81 1a 74 6a f3 e6 02" -a
So, now we see the container for this private key. In this case, we can directly go to Step 4.
However, during my case, in customer’s system the “FindPrivateKey” command failed with an error:
> FindPrivateKey failed for the following reason:
Unable to obtain private key file name
Use /? option for help
In this case we need to follow Step 3.
For some reason the container for the private key is not getting created correctly in the path “Crypto\RSA\MachineKeys\” when the certificate is imported using MMC console.
So, to confirm the above we need to run ProcMon.exe while importing the certificate using MMC.
ProcMon can be downloaded from the link - https://technet.microsoft.com/en-us/library/bb896645.aspx
It is just a simple EXE and no installation is required.
Launce the EXE and add a new filter – Path Contains “Crypto\RSA\MachineKeys\”
Now, when we import the certificate again using MMC, we see an “Access Denied” message in ProcMon when MMC.exe is trying to create a file in the folder “Crypto\RSA\MachineKeys\”.
Double clicking on the entry, shows us the user id that tried to create the file.
This means that the user id does not have access to create a file in the “MachineKeys” folder.
So, we need to log in to the Local Administrator account and provide full access to that user on the folder “C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys”.
Now, we can import the certificate once again using the MMC console. This time when we use the “procmon.exe” while importing we should see something like this.
All that is left is now to provide READ permission to the user account, under which the application is running, using the tool cacls.exe or icalcs.exe.
In my case, the customer had an application hosted on IIS, which was running under the app pool account – “Network Service”
So, I had to provide “Network Service” the read access to the container.
From an admin command prompt run the command:
Cacls.exe “<path>” /e /g “<user>”:R
4551b874c4b7feb55_3b447ade-967e-4fc9-abcf-4a1932c76845" /e /g "Network Service":R
processed file: C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\20aa7ccd097d2e94
This will provide the desired user account read access to the container of the private key and thus avoid the “KeySet does not exist” error.
I hope this helps!
Saurav Dey (MSFT)