After computer restart, 'System.Security.Cryptography.CryptographicException' : Keyset does not exist - c#

I am using following code to sign the data:
RSACryptoServiceProvider csp;
X509Store my = new X509Store(StoreName.My, StoreLocation.LocalMachine);
my.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 cert in my.Certificates)
{
if (cert.Subject.Contains(certSubject))
{
csp = (RSACryptoServiceProvider)cert.PrivateKey;
}
}
csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
First time after installing the certificate to my local machine works fine but when I try to sign after the computer restarting it throws an exception. What could be the possible reason, please help.

I had the same issue. IIS Express running in my account was able to access the private key of the certificate on the day I was importing it on the local machine but not after a restart. The way I was able to fix was by explicitly grant full rights to my account in the certlm console (even thou my account was already in the local administrators group which had full-rights on that private key).

Related

Certificate private key permissions in .NET 6

I'm trying to import a certificate with private key into the Windows Certificate Store. I can successfully import the certificate using the below
X509Certificate2 certificate = new(certByteArray, certPassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
X509Store store = new(StoreName.TrustedPeople, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
But the problem I've got is, how to give a user access to the private key programmatically.
I've found these links helpful:
https://www.pkisolutions.com/accessing-and-using-certificate-private-keys-in-net-framework-net-core/
CngKey Assign permission to machine key
Set Certificate PrivateKey Permissions in .NET 5
I can grant access via the UI with certlm.msc > Drag certificate to Personal store > Right click certificate > All Tasks > Manage private keys > Add the user and permission
But I need to do this programmatically
There are changes from .NET Full Framework which is where the examples come from. I've spent more than a day on it, tried multiple certificates, certificate is definitely marked as exportable and running VS as administrator. I'm happy with a Windows only solution
This is about as close as I've got
const string NCRYPT_SECURITY_DESCR_PROPERTY = "Security Descr";
const CngPropertyOptions DACL_SECURITY_INFORMATION = (CngPropertyOptions)4;
X509Store trustedPeopleStore = new(StoreName.TrustedPeople, StoreLocation.LocalMachine);
trustedPeopleStore.Open(OpenFlags.ReadWrite);
var certificates = trustedPeopleStore.Certificates.Find(X509FindType.FindByThumbprint, "xxxxxxxxxxxxxxxxxxxxxx", false);
RSA rsa = certificates[0].GetRSAPrivateKey();
RSACng rsaCng = rsa as RSACng;
CngProperty prop = rsaCng.Key.GetProperty(NCRYPT_SECURITY_DESCR_PROPERTY, DACL_SECURITY_INFORMATION);
I can see the rsaCng.Key present in debug, but it fails on the next line (it definitely is exportable) getting the property with
Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'Key not valid for use in specified state.'
I've also read comments that you shouldn't try setting the acl directly on the file, but not sure if that is correct or not
See this code project post for some example code that grants access programmatically (specifically look at the "AddAccessToCertificate" method).
Check this for more info: Programmatically adding certificate to personal store

Identityserver fails to load selfsigned certificate

I'm trying to set a Certificate for identityserver and it keeps failing with a "no access to private key error".
Taking it out of identityserver, the following code throws an access denied error
static X509Certificate2 GetCertificateFromDisk()
{
using (var stream = File.Open(#"patht-to-pfx", FileMode.Open))
{
var cert = new X509Certificate2(ReadStream(stream), "password", X509KeyStorageFlags.MachineKeySet);
return cert;
}
}
When running the code as administrator it works fine, not when running it under my own account. Eventually I want to run it as localsystem.
I even added 'Everyone' under the certificates private key permissions in my local computer certificate store,
screenprint here
... still I get the exception.
What is wrong here? Going Crazy about it
Update
Great tips from CryptoGuy in the answer below. Important note: Opening the file is not correct only Identityserver3 still failed when getting the certificate from the store. What made it work was to regenerate the certificate using Keith Sparkjoy's tool SerfCert. My previous certificate was generated using powershell. So keep in mind that powershell certificates have issues with accessibility of private key. Thanks to Keith for the tool!
There are few things to consider.
1) you are performing write access to Local Machine store. X509KeyStorageFlags.MachineKeySet attempts to save private key to Local Machine store. Therefore, you need administrator permissions to write there. You should remove this flag to perform read-only access
2)
Documentation says that adding permissions in MMC (manage private key-option on a certificate) should allow this, but it doesn't seem to work
it works on an already saved private keys.
What you really should do is to import certificate and private key to Local Machine store and then configure your application to reference installed certificate.
3) if your application runs under unpriveleged account and the key don't need to be shared, then you should use Current User store.

Cannot import certificate pfx with private key to store from .net c# 3.5 on windows server 2012

I am attempting to load a certificate with private key from a pfx file and import it to the LocalMachine/My (Personal) certificate store. My code works fine except that when I view the certificate in the store it says
"The associated private key cannot be found"
and further, certutil says
"Cannot find the certificate and private key for decryption"
The strange part is that my code works fine on Windows 7 development box but not on Windows Server 2008 R2 or 2012. Also strange that if I manually import the pfx file using mmc, the private key seems to persist properly.
Here is the code I am using to load the file and import :
// load the certificate from pfx file
X509Certificate2 cert = new X509Certificate2(filePath, pfxPassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
// import to the store
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite); //tried MaxAllowed as well
store.Add(caCert);
store.Close();
Any ideas? For background info, I am also generating the certificate in code at an earlier step using BouncyCastle. I ran into some problems persisting the private key during that step but was solved with the answer from this question. Also the code that is attempting the import is running as administrator.
A little time away from this problem helped me refine my investigation. I tracked down the private key file for the imported certificate in C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
and found that the file had no owner and no permissions set (not even for Administrators or System). Modifying these permissions manually caused the "associated private key" message to go away when viewing the cert in the store.
That led me to modify my code to set permissions on the private key before attempting to import it into the store :
https://stackoverflow.com/a/4902009/332610
hooray!

Can't Get Current User Certificate From X.509 Store

I am Developing Asp.net application in Which I Want to Read Current user Certificate From x509Store...Its Working Fine For my Local Machine .. When I Deploy application on IIS...than I Can't Pick Current user Certificate which I will Use for application authentication...
This Is Following Code for Working Fine for Local System..
public X509Certificate2 selectCert(StoreName store, StoreLocation Location , string windowTitle, string windowMsg)
{
X509Certificate2 certSelected = null;
X509Store x509Store = new X509Store(store);
x509Store.Open(OpenFlags.ReadWrite);
X509Certificate2Collection col = x509Store.Certificates;
X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(col, windowTitle, windowMsg, X509SelectionFlag.SingleSelection);
if (sel.Count > 0)
{
X509Certificate2Enumerator en = sel.GetEnumerator();
en.MoveNext();
certSelected = en.Current;
}
x509Store.Close();
return certSelected;
}
Here x509Store.Certificates Return Some Collection of Current User Certificate..
But when I Run Deployed application In ISS. x509Store.Certificates Give Empty Collection at Sever...For Current User & I've checked my personal store (via certmgr.mmc) and I'm sure that I have the certificates...Crucial Problem Please Solve Out...I can't Understand .. What is happened...
Thanx
Your IIS app must be running under the ASP .net built in account in IIS, which does not have permission to access the certificate stores.
One way to solve it is to change the user to some other wihch has permissions, but it will lead to security issues.
A better approach but more complex is to have a service executed with elevated privileges which accepts incomming TCP/UDP/pipes connections from local machine, retrieves the certificates and pass them out, in this way you can call safely that service from your asp.net page without giving it elevated permissions
If you have installed the certificate as CurrentUser, only services running under your username will have access.
In order to access the certificate for all usernames in a machine, you will have to install the certificate as LocalMachine and retrieve the same using LocalMachine
for more info read

How to create personal certificate

i am using this code for certificate generation o local machine.
X509Certificate2 certificate = new X509Certificate2(cerFilePath,password);
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();
output shows it's created but it is not in the personal tab of certmanager but if i use Store Name other than My (example: Trusted Publisher ) in same program, certificate is available in cert manager under that storename.
but i need certificate for personal use.
what is going wrong?
If you use the "LocalMachine" context, you must have "Elevated Privileges" (Run the application as an administrator if needed).
Both "LocalMachine" and "CurrentUser" have a store named "Personal" (My) !
You can browse the "LocalMachine" store with "certlm.msc", and use "certmgr.msc" to browse "CurrentUser" store.

Categories

Resources