Reputation: 469
I have a WinForms application that consumes a WCF, and pass as a parameter to a function a certificate:
mySvcClient.SendDocument(cert.Export(X509ContentType.SerializedCert, "password"));
...
In WCF service, I recreated the certificate from the array of bytes:
public void SendDocument (byte[] binaryCert)
{
X509Certificate2 cert = new X509Certificate2(binaryCert, "password");
...
But when using the certificate to sign a xml, I got the error "Keyset does not exist":
if (cert.HasPrivateKey) // WORKS!!!
{
signedXml.SigningKey = cert.PrivateKey; // THROW "keyset does not exist" EXCEPTION
...
In my computer, the application works 100%! But in the WebServer, I got this error!
The question is: even X509Certificate2 recreated from an array of bytes, I need some special permission to access private key?
Thank you!
Upvotes: 47
Views: 78155
Reputation: 19
I was getting this error when I had deployed my code to two load-balanced servers, but only on one of the servers. It would work on the other server. I think the important thing here is to import your certificate to My/LocalMachine so that you have the ability to manage the private keys. I deleted my certificate in the other locations before doing this. The weird thing was that the certificate was set up on the servers identically, and I was able to confirm that the private keys were also in the same relative location using the FindPrivateKey tool. On the server that was causing the issue, I simply:
It's weird that both servers didn't require this, but I thought it was worth mentioning that sometimes server configuration has inconsistencies that need to be accounted for.
Upvotes: 0
Reputation: 21
You just need to change the flags!
Wrong:
var certificate = new X509Certificate2(filePath, password,
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Correct:
var certificate = new X509Certificate2(filePath, password,
X509KeyStorageFlags.EphemeralKeySet);
The short explanation is that the default X509KeyStorageFlags store the certificate's private key file is created on a disk. Which causes concurrency and security problems. EphemeralKeySet doesn't create any file on disk, it temporarily loads the key from PFX and unloads when finished. If you want to read more on X509KeyStorageFlags and good practices, I strongly recommend this blog by About Vadims Podāns.
Upvotes: 2
Reputation: 353
Due to the nature of private keys being a sensitive information, they are not stored in the same location with certificates. Analogous to Vano Maisuradze's method, you can use Process Monitor utility to capture traces to system services and identify location of the file on the file system. Afterwards grant read permissions to the user on that file and 'Keyset does not exist' error should be solved. You can also find the user that is running the thread in procman.
Upvotes: 0
Reputation: 410
For local development, make sure the user has permissions to access the certificate, especially if you're installing it in the Local Machine store.
This was the case for me when debugging it using Rider.
Upvotes: 6
Reputation: 105
I had the same issue on c# console application and after reading answeres here I thought that problem was in permissions. Then I run visual studio as administrator and it worked.
Upvotes: 0
Reputation: 295
If you are able to debug the application, try running the IDE on admin mode..you can also add new users from MMC.
Upvotes: 0
Reputation: 905
couple of troubleshooting steps:
Upvotes: 2
Reputation: 4541
I was facing the same issue, and I don't know how(shame on me), but it worked:
var certificate = new X509Certificate2(filePath, password,
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
certificate.PrivateKey; // before: error "KeySet does not exist"!
using (certificate.GetRSAPrivateKey()) { } // pure black magic
certificate.PrivateKey; // after: just works! lol
I hope someone can answer this mystery.
Upvotes: 22
Reputation: 15193
Application Pool Identity accounts don't have access to the certificate store by default.
Either you change to Network Services
account as pointed by Vaibhav.Inspired or you give access to the certificate.
To allow access do the following command:
WinHttpCertCfg.exe -g -c LOCAL_MACHINE\MY -s "IssuedToName" -a "AccountName"
Notes:
- The tool may need to be installed first. The setup will place the tool at `C:\Program Files (x86)\Windows Resource Kits\Tools\WinHttpCertCfg.exe`.
- `IssuedName` is the issuer property of the certificate that the application will attempt to access
- The command must be run from command prompt with elevated privileges
Reference :https://support.microsoft.com/en-us/help/901183/how-to-call-a-web-service-by-using-a-client-certificate-for-authentica Step 2
Also you need to enable the Mark this key as exportable
option when installing the certificate.
Upvotes: 0
Reputation: 680
I have faced this issue, my certificates where having private key but i was getting this error("Keyset does not exist")
Cause: Your web site is running under "Network services" account or having less privileges.
Solution: Change Application pool identity to "Local System", reset IIS and check again. If it starts working it is permission/Less privilege issue, you can impersonate then using other accounts too.
Upvotes: 42
Reputation: 429
Vano Maisuradze answer works. If you are looking for the FindPrivateKey tool it is included in Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4, which can be found here: http://www.microsoft.com/en-us/download/confirmation.aspx?id=21459
Once downloaded and extracted, open the project: WF_WCF_Samples\WCF\Setup\FindPrivateKey\CS in Visual Studio and compile it. Then open command prompt and navigate to: WF_WCF_Samples\WCF\Setup\FindPrivateKey\CS\bin
Then continue with Vano Maisuradze answer
Upvotes: 5
Reputation: 5899
If you are using windows server 2008 or windows 7, then you need the permission to read private key.
FindPrivateKey My LocalMachine -n "CN=MyCert" –a
it returns the path: C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys[File Name]
Go to that path and open file properties
Go to security tab
Click on "Edit" then "Add"
In opened dialog write: IIS AppPool\[your application pool name] and click OK
Now your application pool has permission to read this private key.
Upvotes: 48
Reputation: 5399
I think the problem is that you need to add the key to the machine's certificate store.
Upvotes: 2