How to create personal certificate - c#

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.

Related

How to find a certificate in cert store using file's name?

There are different ways for finding installed certificates in cert store and one of them is by using thumbprint:
using X509Store store = new(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates;
using X509Certificate2 cert = certCollection.Find(X509FindType.FindByThumbprint, "139FAA424C85CDCA61E0EB63895B0B3AA395471E", validOnly: true).First();
But I'm trying to find an easier way for the client to find their certificate like using the file's name or sth more reachable than thumbprint. By the way, I don't want them to specify file path and password because they should use an installed certificate hence should look for it in the cert store.

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

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

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).

Installing a pfx file with C# seems different to manually installing it

I have a c# program which installs a pfx file (Code below)
X509Certificate2 cert;
cert = new X509Certificate2(#"myCert.pfx", "password");
if (cert != null)
{
var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
if (!store.Certificates.Contains(cert))
{
store.Add(cert);
}
}
This seems to add the cert into the correct place when I view it in the management console. However I have a websocket server in c# that will pick it out of the store and use it for its ssl connections to the browser however the browsers all fail due to not having authentication to the cert.
However if I were to install it manually (clicking the cert) and installing it to the same location everything works fine.
NOTE:It is Self-Signed
How would I fix this problem
If the certificate is self-signed, you have to use it as well for the HTTPS page that holds the javascript code connecting to the websocket, so the browser can prompt you to accept the certificate.
You can retrieve the certificate using for example:
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certificate = store.Certificates[1];
store.Close();
And then use it for your WebSocket server. I don't know which .NET WebSocket server are you using, but in WebSocketListener is done this way.

Netsh error 1312 after programatically adding certificate to the store

I'm trying to add a certificate to the store programatically using the following code:
var certPath = string.Format("{0}//{1}", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),"fileName.pfx");
var cert = new X509Certificate2(certPath, "Password");
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();
I check in MMC and the certificate is added.
If I now run in a command prompt with admin privileged:
netsh http add sslcert ipport=0.0.0.0:<port> certhash=<Thumbnail> appid={00000000-0000-0000-0000-000000000000}
Then it throws a 1312 error, "A specified log-on session does not exist. It may already have been terminated."
If I add the certificate via the import function in MMC, then the above command works.
Can anyone please help?
The issue is the way in which windows is storing the private key.
To do this programatically in .Net, change the following line of code:
X509Certificate2 cert = new X509Certificate2(path, "password",
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
As per this question: Inserting Certificate (with privatekey) in Root, LocalMachine certificate store fails in .NET 4
We ended up using WIX to inject the certificate into the store on installation. It seemed to work nicely.

Categories

Resources