Service failure with CryptographicException - Keyset does not exist
Problem Statement:
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 information:
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.
Troubleshooting:
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.
Step 1:
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.
Step 2:
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 - 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
Example:
>> 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
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\20aa7ccd097d2e94551b874c4b7feb55
_3b447ade-967e-4fc9-abcf-4a1932c76845
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.
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.
Step 4:
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
Example:
>cacls.exe "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\20aa7ccd097d2e9
4551b874c4b7feb55_3b447ade-967e-4fc9-abcf-4a1932c76845" /e /g "Network Service":R
processed file: C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\20aa7ccd097d2e94
551b874c4b7feb55_3b447ade-967e-4fc9-abcf-4a1932c76845
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!
Created by
Saurav Dey (MSFT)
Comments
Anonymous
November 05, 2015
Had the exact same issue today. This article really saved the day. Thank you very much! For some reason I didn’t had the right permissions. Even while my user account is a member of the administrator group.Anonymous
June 03, 2016
Thank you so much! 2 solid days of searching for a solution to this issue. This was a very thorough step-through of how to solve this issue. If it were a stack overflow answer I would have upvoted it and told all my colleagues to do the same!Anonymous
September 21, 2016
The FindPrivateKey location specified, " \WCF\Tools\FindPrivateKey\CS\ and open the .sln file. Build the project to generate the .exe in the bin folder.", is incorrect. It's actually under \WCF\Setup\FindPrivateKey\CS.Anonymous
June 27, 2017
I had one more step to perform because access was denied changing the Read permission. I needed to change the object ownership FROM System to the Administrator account, make the change and then change the Ownership back to System. Then it worked- Anonymous
June 27, 2017
Some clarification. Step 2 done, skipped step 3, step 4 Failed due to 'Access Denied'. Needed to change ownership as per above. This was on an Azure VMSS VM for application running via Service Fabric. The certificate itself was provisioned onto the VM via KeyVault which I believe is why there was no issue involving step 3.
- Anonymous