I'm trying to add certificates but the Add function doesn't seem to do anything.
I have two certificates. Both I can add manually by right clicking and saving to the personal "testStore" store but they don't get saved when I try to add them programmatically. I even added just one of them, and the X509Store object contains it just as expected, but when I call .Add(cert), nothing gets saved there.
//I've already added 1 cert manually
X509Certificate2 cert2 = new X509Certificate2(#"C:\temp\Cert2.cer");
X509Store store = new X509Store("testStore", StoreLocation.CurrentUser);
store.Open(OpenFlags.MaxAllowed);
//here store.Certificates has the one Certificate I added manually as expected.
store.Certificates.Add(cert2);
//here store.Certificates still only has the first certificate, cert2 still isn't there..
store.Close();
Am I missing something?
Edit
I've also tried using StorePermission (as below) and also tried impersonating the administrator account and those didn't help either
StorePermission sp = new StorePermission( PermissionState.Unrestricted);
sp.Flags = StorePermissionFlags.AllFlags;
sp.Assert();
I got it to work... It turns out you should use store.Add() instead of store.Certificates.Insert();
//When LocalMachine is used, .Add() requires that you run the app as an administrator in order to work.
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
X509Certificate2 cert = new X509Certificate2("C:\\test\\test.cer");
store.Open(OpenFlags.MaxAllowed);
store.Add(cert);
store.Close();
Try with this flag:
store.Open (OpenFlags.ReadWrite);
http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.openflags(v=vs.110).aspx
Related
I am using a Gemalto Smart card to sign XML documents.
I have a method which returns the certificate and searches by the thumbprint that is hard coded.
I am unable to obtain the private key from that Smart card and sign the doc with it.
It returns null when I debug the app.
My goal is to get the private key and then ask the user for the PIN to authorize the signing of the document.
public static X509Certificate2 GetDefaultCertificateStoredOnTheCard()
{
X509Store store = new X509Store("MY", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, true);
// by thumbprint, there is only one
certs = certs.Find(X509FindType.FindByThumbprint, "6BB4F9D483206F44A992799541114536579CF2B3", true);
if (certs.Count == 0)
{
throw new ArgumentException("Please insert smart card to obtain certificate.");
}
X509Certificate2 cert = certs[0];
RSACryptoServiceProvider key;
if (cert.HasPrivateKey)
{
// software cert
key = cert.PrivateKey as RSACryptoServiceProvider;
}
else
{
// certificate from smartcard
CspParameters csp = new CspParameters(1, "Microsoft Base Smart Card Crypto Provider");
csp.Flags = CspProviderFlags.UseDefaultKeyContainer;
key = new RSACryptoServiceProvider(csp);
}
return cert;
}
As you can see if the key is null, set the key to use the Microsoft Base Smart Card Crypto Provider.
I have noticed on device manager that my Smart Card Reader is Microsoft Usbccid Smartcard Reader.
Not sure if I should set something else here , it brings this window and an error with it.
The very purpose of a smart card is to protect confidential data. There are no more confidential data than the private key (often this never leaves the smart card), so it is a sign of correct functioning, that you don't get it.
Actually you have to let the smart card do the signature, probably by sending the hash value of your XML document.
Just to answer my question. The whole problem was the .dll. I installed wrongly another provider of electronic signature and it is using that .dll instead of the one that I used for the signing.
When I understood that, it was easy fix, just uninstall the app for the provider which uses the wrong .dll.
I have a .p7b file with a few certificates and i want to install them in the "Enterprise Trust" Store. A program i want to use expects it there.
I have writte code in c# which extract all the certificates from the file and installs them into a X509Store ("Storename.My") which works.
If i try to use the same code to write in a different store it (which already exists) it creates a new empty store and writes in there.
The StoreName.My is taken from system.Security.Cryptography.X509Certificates public enum StoreName, but there is no option for the "Enterprise Trust" store.
So i tried to use the constructor where i can give the StoreName as a string.
I use the certmgr from windows to check what certificats are stored in which stores.
// open file
var certificateStore = new CmsSignedData(new
FileStream(_tempFileName.ToString(), FileMode.Open));
// get all certificats
IX509Store x509Certs = certificateStore.GetCertificates("Collection");
var a = new ArrayList(x509Certs.GetMatches(null));
// this works
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
// this doesnt work
// var store = new X509Store("Enterprise Trust", StoreLocation.CurrentUser);
// open store
store.Open(OpenFlags.ReadWrite);
// write in store
foreach (object o in a) {
var cert = (Org.BouncyCastle.X509.X509Certificate)o;
var cert509 = new X509Certificate2();
cert509.Import(cert.GetEncoded());
store.Add(cert509);
}
store.Close();
How do i write correctly in the a store which isnt the StoreName enum?
If you want to be sure you aren't creating a new store, you can use the OpenFlags value OpenExistingOnly. Asserting that flag and checking for, e.g. "Trust2" yields System.Security.Cryptography.CryptographicException: The system cannot find the file specified. Therefore we get the best level of assurance that "Trust" is the right answer by specifying it as:
using (X509Store store = new X509Store("Trust", StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadWrite | OpenFlags.OpenExistingOnly);
...
}
(Note that this is less good to use on Linux (.NET Core), because only Windows pre-initializes the stores)
We can get confirmation on the programmatic name to the display name via the certutil.exe command-line utility:
>certutil -store trust
trust "Enterprise Trust"
CertUtil: -store command completed successfully.
(I just don't have anything in that store)
This is probably a very basic error, but i am pulling my hair trying to understand why this is happening.
I have a check against the store certificates if it contains a certain certificate with a name. If it doesnt, then update a label.text.
It does the check just fine and it finds it, but no matter what i do it doesnt handle if it isnt there. Its not doing anything. No text beeing displayed. I have also tried a simple else without the (!mCert) but still no go.
// Certificate controls
X509Store store = new X509Store("My", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 mCert in store.Certificates)
{
if (mCert.Issuer.Contains("Cert-Name"))
{
label3.Text = "Found certificate";
}
else if (!mCert.Issuer.Contains("Cert-Name"))
{
label3.Text = "Didnt find the certificate";
}
}
So the else if statement isnt doing anything. Even if i just put an else instead there it isnt updating the label3.text.
If the store is empty and cant find any certificates the foreach will never run, thats why the if statements never get processed.
Adding this before the foreach will solve it
if (store.Certificates.Count==0)
"My" store of local machine is very likely to be empty (unless you install things such as IIS, where the installer generates test certificates).
Thus, switch to other stores, such as using StoreName enumeration,
https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename(v=vs.110).aspx
You can always open MMC to see stores and certificates,
https://msdn.microsoft.com/en-us/library/ms788967(v=vs.110).aspx
I have the following code where SIGNED_FILENAME is a constant pointing to an existing pfx file that contains the private key.
X509Certificate2 cert = new X509Certificate2(SIGNED_FILENAME, PASSWORD, X509KeyStorageFlags.MachineKeySet);
RSACryptoServiceProvider certRsa = cert.PrivateKey as RSACryptoServiceProvider;
When I use code to add permissions to the private key I find that they are set on the file specified in certRsa.CspKeyContainerInfo.UniqueKeyContainerName. When I view the certificate permissions in the Certificates mmc snap-in however there are no new permissions set.
When I set the keys manually via the Certificates mmc snap-in I find that the private key it sets the permissions on is different than the one I found in the UniqueContainerName property mentioned above.
TLDR: Each time I run those two lines of code the key container file changes.
Why would this be happening and how can I set the permissions on the same key that the Certificates mmc snap-in does?
Apparently because I was opening it from a file each time the key container was being re-generated (or something). Here is the code that works:
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2 c = store.Certificates
.Find(X509FindType.FindBySubjectName, SIGNED_SUBJECT, true)
.Cast<X509Certificate2>()
.FirstOrDefault();
store.Close();
RSACryptoServiceProvider rsa = c.PrivateKey as RSACryptoServiceProvider;
Console.WriteLine("Certificate thumbprint:" + c.Thumbprint);
Console.WriteLine("From machine key store?: " + rsa.CspKeyContainerInfo.MachineKeyStore);
Console.WriteLine("Key container name: " + rsa.CspKeyContainerInfo.KeyContainerName);
Console.WriteLine("Key unique container name: " + rsa.CspKeyContainerInfo.UniqueKeyContainerName);
Previously when running the code snippet from my original post (where I open the certificate as a file) the key info that prints to the console would change each time. Running the modified code shows the same info each time.
i want to obtain the CN of the certificates stored in the MY store as i want to verify if the certificate exists or not in that store.
I don't know the which method should be used to perform this task.
I tried using below code but it doesn't works
X509Certificate2Collection cers = store.Certificates.Find(X509FindType.FindBySubjectName,"Root_Certificate",false);
if(cers.Count>0)
{
//certificate present
}
else
{
//certificate not present
}
Does the subjectName gives CN?
is there any other method?
Please suggest me how to check whether a particular certificate is present or not and i want to do it using CN.
You could use the store.Certificates.Find(X509FindType.FindBySubjectName, "SubjectName", false)
function to search for a certificate by its subject name. Do NOT include "CN=" in the subject name.
To search more specific you could use the thumbprint to search for your certificate.
The following code sample demonstrates this:
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.IncludeArchived);
foreach (var c in store.Certificates)
{
Console.Out.WriteLine(c.Thumbprint);
Console.Out.WriteLine(c.Subject);
}
// Find by thumbprint
X509Certificate2Collection col =
store.Certificates.Find(X509FindType.FindByThumbprint, "669502F7273C447A62550D41CD856665FBF23E48", false);
store.Close();
I've added a foreach loop to the code sample to iterate over all certificates in the selected store.
Your certificate must be listed there. If not, you probably use the wrong store.
Note, there is a My store for the Machine and the Current User. So, be sure to open the right store.
To get the thumbprint of your certificate follow these steps:
Open certmgr.msc.
Double click on your certificate.
Go to the details tab.
Under thumbprint you will find the thumbprint of your certificate.
Hope, this helps.