CryptographicException 'Keyset does not exist', but only through WCF

Viewed 222588

I have some code that makes a call to a third party web service that is secured using X.509 certification.

If I call the code directly (using a unit test) it works without any problems.

When deployed, this code will be called via a WCF Service. I have added a second unit test that calls the WCF Service, however this fails with a CryptographicException, message "Keyset does not exist" when I call a method on the third party web service.

I presume that this is because my WCF Service will be attempting to call the third party web service using a different user to myself.

Can anyone shed any additional light on this issue?

22 Answers

It will probably be a permissions problem on the certificate.

When running a unit test you are going to be executing those under your own user context, which (depending on what store the client certificate is in) will have access to that certificate's private key.

However if your WCF service is hosted under IIS, or as a Windows Service it's likely it will be running under a service account (Network Service, Local Service or some other restricted account).

You will need to set the appropriate permissions on the private key to allow that service account access to it. MSDN has the details

The Answer from Steve Sheldon fixed the problem for me, however, as I am scripting certificate permissions with out a gui, I needed a scriptable solution. I struggled to find where my private key was stored . The private key was not in -C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys , eventually I found that it was actually in C:\ProgramData\Microsoft\Crypto\Keys. Below I describe how I found that out:

I tried FindPrivateKey but it could not find the private key, and using powershell the $cert.privatekey.cspkeycontainerinfo.uniquekeycontainername was null/empty.

Luckily, certutil -store my listed the certificate and gave me the details I needed to script the solution.

================ Certificate 1 ================ Serial Number: 162f1b54fe78c7c8fa9df09 Issuer: CN=*.internal.xxxxxxx.net NotBefore: 23/08/2019 14:04 NotAfter: 23/02/2020 14:24 Subject: CN=*.xxxxxxxnet Signature matches Public Key Root Certificate: Subject matches Issuer Cert Hash(sha1): xxxxa5f0e9f0ac8b7dd634xx Key Container = {407EC7EF-8701-42BF-993F-CDEF8328DD} Unique container name: 8787033f8ccb5836115b87acb_ca96c65a-4b42-a145-eee62128a ##* ^-- filename for private key*## Provider = Microsoft Software Key Storage Provider Private key is NOT plain text exportable Encryption test passed CertUtil: -store command completed successfully.

I then scanned c\ProgramData\Microsoft\Crypto\ folder and found the file 8787033f8ccb5836115b87acb_ca96c65a-4b42-a145-eee62128a in C:\ProgramData\Microsoft\Crypto\Keys .

Giving my service account read access this file fixed the issues for me

I was getting this same error in my PowerShell scripts. The fix for me was simply to run the script as administrator. So make sure whatever app you're running that attempts to retrieve the certificate is running as admin.

I just reinstalled my certificate in local machine and then it is working fine

This is the only solution worked for me.

    // creates the CspParameters object and sets the key container name used to store the RSA key pair
    CspParameters cp = new CspParameters();
    cp.KeyContainerName = "MyKeyContainerName"; //Eg: Friendly name

    // instantiates the rsa instance accessing the key container MyKeyContainerName
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
    // add the below line to delete the key entry in MyKeyContainerName
    // rsa.PersistKeyInCsp = false;

    //writes out the current key pair used in the rsa instance
    Console.WriteLine("Key is : \n" + rsa.ToXmlString(true));

Reference 1

Reference 2

This issue is got resolved after adding network service role.

CERTIFICATE ISSUES 
Error :Keyset does not exist means System might not have access to private key
Error :Enveloped data … 
Step 1:Install certificate in local machine not in current user store
Step 2:Run certificate manager
Step 3:Find your certificate in the local machine tab and right click manage privatekey and check in allowed personnel following have been added:
a>Administrators
b>yourself
c>'Network service'
And then provide respective permissions.

## You need to add 'Network Service' and then it will start working.

This issue is old but it surfaced to me today and all the readings I did refer to permission, but that wasn't the case with me. It turned out that the new (Windows Service) project I created had this option enabled by default. Properties-->Build-->Prefer 32-bit.

By unchecking this option and re-deploying this error went away and everything worked fine.

Hope this helps someone whose issue isn't permission-related.

I was having this exception when signing a file using SNK data. The trick is to set the KeyNumber to 2 (Signature) in the CspParameters, e.g.:

$params = New-Object System.Security.Cryptography.CspParameters
$params.KeyNumber = 2

$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider($params)
$rsa.ImportCspBlob($snk)
$signature = $rsa.SignData($inputBytes, [Security.Cryptography.HashAlgorithmName]::SHA256, [Security.Cryptography.RSASignaturePadding]::Pkcs1)

I experienced this exception in a race condition. I used the same PFX file about 10k times in parallel processes (maybe 50 processes in parallel) and the exception appeared in about 1 % of the cases. I assume that the processes share the same private key file and the handle counter sometimes counts wrong or something the like, and then the key file is deleted although another process still needs it.

Catching the exception and retrying to use the same X509Certificate2 object didn't help. I didn't investigate further for now, but I believe it would help to leave out the parallelization.

Related