X509Certificate - Keyset does not exist - c#

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!

If you are using windows server 2008 or windows 7, then you need the permission to read private key.
use FindPrivateKey tool to find path.
For example:
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.

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.

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.

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

I think the problem is that you need to add the key to the machine's certificate store.

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.

couple of troubleshooting steps:
Run your program as Administrator
If it is web app deployed in IIS -> then add the IIS_IUSRS to the Certificate permissions. Select certificate in Personal, Right Click-> Manage Private Keys -> Add the user.
Run Visual Studio in Admin mode if in Debug to get this problem sorted out

If you are able to debug the application, try running the IDE on admin mode..you can also add new users from MMC.

For local development, make sure the user has permissions to access the certificate, especially if you're installing it in the Local Machine store.
Open certificate manager (mmc.exe or certlm)
Go to certificate
Right Click > All Tasks > Manage Private Keys
Assign permission for current user
Done
This was the case for me when debugging it using Rider.

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.

Related

Asp.net core keep using the expired certificate

Recently, my localhost certificate is expired, I have gone to "sertmgr.msc" remove all localhost certificate and restart the VS and add a new localhost certificate to windows.
But when am I running my application again, still use the old expired certificate not the new one, does anyone know how to fix that?
I have already run the command show below.
dotnet dev-certs https --clean
dotnet dev-certs https --trust
Expired Cert
Cert In Cert Manage
I managed to hack my way around this issue:
Before you do anything, clean the old certificate and generate a new trusted one.
dotnet dev-certs https --clean
dotnet dev-certs https --trust
And if the process above fails, manually remove the certificates before retrying the clean/trust commands.
Get the User Secrets ID of the Web Application you're having trouble with. Search for UserSecrets.UserSecretsIdAttribute(" in your project folder and take the GUID.
Go to %APPDATA%\Microsoft\UserSecrets and open the folder containing the GUID of the problematic project you are struggling with and leave it open.
Create a new Asp .Net Core project, get its secrets GUID, go to the corresponding secret folder (%APPDATA%\Microsoft\UserSecrets\GUID), and open the file secrets.json. You should see something like this
{
"Kestrel:Certificates:Development:Password": "8353f2ec-3cc0-4052-9776-9585b6abd346"
}
Copy that setting from the newly created project secrets.json and use it to override the development password on the secrets.json of the broken project
This way, I've managed to get my old project to use the newly generated certificate. It is hacky, but it works
Based on Pedro's answer,
I used:
dotnet dev-certs https --clean
dotnet dev-certs https --trust
to clean/replace the old certs.
Then I went to:
%APPDATA%\Microsoft\UserSecrets
And deleted all the folders found there.
Now my application runs without complaining.
Creating a new .net core 6 application and running it didn't create a new folder, so I don't know if it's no-longer required.
I assume you're using IIS Express to host your application. If so, it sounds like you're missing linking the certificate to your application(s) as described in this blog post:
Go to C:\Program Files (x86)\IIS Express and run the following from the command line, entering the proper port number and the new certificate thumbprint:
IisExpressAdminCmd.exe setupsslUrl -url:https://localhost:PORT/ -CertHash:THUMB
I want to provide some context about Pedro's answer on Windows.
Thanks to this article and some testing, I found out that the password specified by Kestrel:Certificates:Development:Password setting applies to a project dedicated certificate found in %APPDATA%\ASP.NET\Https.
Answer: When you delete either the password setting or the project certificate, Kestrel starts working as expected, looking for a proper certificate installed with dotnet dev-certs command. I think the most convenient is to delete all project certificates from %APPDATA%\ASP.NET\Https folder.
This seems to be a Visual Studio problem when the project was created. However, I could not reproduce it with my current version of Visual Studio 2019.
In conclusion, the problem is not about the dotnet dev-certs command, but rather about hidden logic on how Visual Studio creates the project and how Kestrel handles certificates.
I had the same problem with different types of projects:
ASP.NET Core with Angular template created with VS Code.
ASP.NET Core Web API created with Visual Studio.
When the problem comes with the ASP.NET Core with Angular template on Windows, you can try:
Stop the application.
Open the File Explorer.
Paste %APPDATA%\ASP.NET\https into the address bar and press enter.
It will navigate automatically to C:\Users\[your_user]\AppData\Roaming\ASP.NET\Https
Delete the your_npm_package_name.pem and your_npm_package_name.key files.
your_npm_package_name: Is the name property value of the package.json file of your Angular client app.
Open MMC (Start > Run > MMC). Open the Certificates Snap-in (File > Add/Remove Snap-in).
Select My Current Account when prompted.
Under Certificates - Current User select the Personal\Certificates folder.
Locate and select the certificate for localhost domain and with the Friendly Name "ASP.NET Core HTTPS development certificate".
Delete the localhost certificate.
Repeat the localhost certificate deletion process for al localhost certificate with the Friendly Name "ASP.NET Core HTTPS development certificate" under the Personal\Certificates folder and the Trusted Root Certification Authorities\Certificates folder too.
Start your application again.
Your application's pem and key files will be automatically regenerated.
This solution is also valid for other advanced templates like Jason Taylor's Clean Architecture Solution Template.
When the problem comes with a ASP.NET Core Web API project created with Visual Studio and enabling Docker (not always).
After trying all the alternatives of this question and using the Generate self-signed certificates with the .NET CLI and Enforce HTTPS in ASP.NET Core guides from Microsoft, I found that my expired certificate was located in the C:\Users[your_user]\AppData\Roaming\ASP.NET\Https folder with the name my_api_assembly_name.pfx.
How did I regenerate my certificate?
Stop the application.
Open the File Explorer.
Paste %APPDATA%\ASP.NET\https into the address bar and press enter.
It will navigate automatically to C:\Users\[your_user]\AppData\Roaming\ASP.NET\Https
Delete the your_my_api_assembly_name.pfx.
Open MMC (Start > Run > MMC). Open the Certificates Snap-in (File > Add/Remove Snap-in).
Select My Current Account when prompted.
Under Certificates - Current User select the Personal\Certificates folder.
Locate and select the certificate for localhost domain and with the Friendly Name "ASP.NET Core HTTPS development certificate".
Delete the localhost certificate.
Repeat the localhost certificate deletion process for al localhost certificate with the Friendly Name "ASP.NET Core HTTPS development certificate" under the Personal\Certificates folder and the Trusted Root Certification Authorities\Certificates folder too.
Open your Windows Terminal as administrator.
Run dotnet dev-certs https -ep $env:USERPROFILE\AppData\Roaming\ASP.NET\Https\your_api_assembly_name.pfx -p your_user_secrets_id:
Change your_my_api_assembly_name with your own assembly name.
How to retrieve your_user_secrets_id?
Open your_project.csproj with a text editor (or double-click on the project in Visual Studio Solution Explorer) and look for a node called UserSecretsId. Inside this node there is your your_user_secrets_id.
Otherwise, if you don't have the UserSecretsId node in your project file:
Open the File Explorer.
Paste %APPDATA%\Microsoft\UserSecrets into the address bar and press enter.
It will navigate automatically to C:\Users\[your_user]\AppData\Roaming\Microsoft\Secrets
Open the folder called as the GUID of your project (you can get yours inside your your_solution.sln file).
Open the secrets.json file and find a property called Kestrel:Certificates:Development:Password. The value of this property is your your_user_secrets_id.
Your application's pfx file will be automatically regenerated.
Run dotnet dev-certs https --trust.
You will be prompted to install a new certificate for localhost.
Click Yes.
Start your application again.

InvalidOperationException: Key type not specified on AspNetCore using cermgr installed certificate

I'm trying to deploy an AspNetCore app that uses IdentityServer4 to IIS and when I fire it up I get the InvalidOperationException: Key type not specified error. I used the MMC to load certmgr and imported the self signed certificate I created with a password but its not working. Any ideas?
I just had this problem myself. The fix for me was going back into certmgr and right click on the cert, then All Tasks, then Manage Private Keys, and add IIS_IUSRS. Depending on how your IIS app pool is configured for your website you might have to also add user "IIS APPPool{apppoolname}" as well. And for a really old, or misconfigured IIS setup, perhaps Local Service and/or Network Service.

Manual update for signed ClickOnce app throws TrustNotGrantedException

I have a ClickOnce deployment which is signed by a certificate obtained from Symantec. The security warning prompt after starting the setup shows the publishers name. So it's trusted. But when calling
ApplicationDeployment.CurrentDeployment.CheckForDetailedUpdate()
I get the TrustNotGrantedException - User has refused to grant required permissions to the application.
If I add my certificate to the Trusted Publishers Store on my machine the exception is not thrown and the CA of Symantec is also added to the store. But obviously I can't add the certificate to the Trusted Publishers Store of our clients who use the app.
The app is first installed from disc and at every start it checks an online update url.
And if I remove the certificates from the Trusted Publishers Store afterwards the manual update still works if I try it again. Are these information also stored elsewhere?
If I don't sign the published ClickOnce app the manual update works.
If I sign the published ClickOnce app with a self signed certificate made with makecert the manual update works.
So there's probably an issue with the certificate?
How can I determine if there's a certificate issue and which steps should I do next?
We are using the InPlaceHostingManager Class now. It's made for installing or updating a ClickOnce deployment. GetManifestAsync() fires the GetManifestCompleted event, which gives you the version number. Then you can call DownloadApplicationAsync() and handle the DownloadApplicationCompleted event. So far this works and no TrustNotGrantedException is thrown.

certMgr.exe not loading the private key of certificate in personal local machine store(Windows 10)

I have an application which runs certmgr.exe to install certificates at localMachine in root and personal folder. Following are the commands I am using
CertMgr.exe -add -all "secure\certs\cacert.crt" -s -r localMachine root
CertMgr.exe -add -all "secure\certs\server.p12" -s -r localMachine my
When I run these commands via command prompt to install these certificates respectively in windows7/8 platform, certificates get install and they work
But when I run the same command on windows 10 platform, certificates get installed in store but they don't work. Following error comes:
ERROR :-2506:Load device private key 'CN=ABB Authentication Server, OU=CSA, O=ABB' from windows store 'MY' failed
ERROR :-2506:Cannot load private key/certificate pair from Windows store
Certificates are proper, I verified this by manually importing the certificates in mmc. When I imported manually, they started working. Clearly I could find that there is some problem with certmgr.exe or the access rights in windows 10 platform. I tried with different "certmgr.exe's" but could not solve the problem.
Ok,
Following code worked for me in .Net:
Dim store As New System.Security.Cryptography.X509Certificates.X509Store(X509Certificates.StoreName.Root, X509Certificates.StoreLocation.LocalMachine)
store.Open(X509Certificates.OpenFlags.ReadWrite)
Dim cert As New System.Security.Cryptography.X509Certificates.X509Certificate2("c:\cert.pfx", "password")
store.Add(cert)
store.Close()
Try to run CertMgr.exe from cmd, with Run As Administrator option by right clicking cmd app, from system32 folder.

Where do I locate certificates generated for local HTTPs server in C#

I am able to generate SSL certificate for local URL.
It is generated successfully as shown in image below,
var certStore = new X509Store(storeName, storeLocation);
But I am unable to locate this certificate inside currentUser directory.
Is it the correct location where SSL certificates are stored? Or am I looking at wrong place?
If I use https://google.com instead of localwebserver this is working fine.
Try to go to RUN > MMC > File > Add/Remove Snapin..
Click on Certificates then click Add..
Choose Computer Account then Local Computer... Then click OK.
You will see all your certificates there..
or you can locate it on your IIS in Server Certificates

Categories

Resources