Smart Card gives null as a value of private key - c#

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.

Related

prevent windows security popup for missing smart cards

I found this article in Rahul's Blog about getting the certificate associated with the inserted smart card.
Rahul suggests this approach:
var smartCardCerts = new List<X509Certificate2>();
var myStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
foreach(X509Certificate2 cert in myStore)
{
if( !cert.HasPrivateKey ) continue; // not smartcard for sure
var rsa = cert.PrivateKey as RSACryptoServiceProvider;
if( rsa==null ) continue; // not smart card cert again
if( rsa.CspKeyContainerInfo.HardwareDevice ) // sure - smartcard
{
// inspect rsa.CspKeyContainerInfo.KeyContainerName Property
// or rsa.CspKeyContainerInfo.ProviderName (your smartcard provider, such as
// "Schlumberger Cryptographic Service Provider" for Schlumberger Cryptoflex 4K
// card, etc
var name = cert.Name;
rsa.SignData(); // to confirm presence of private key - to finally authenticate
}
}
However, if the smart card is not inserted, a Windows Security dialog pops up asking the user to select a smart card device.
Is there a way to prevent this popup and instead throw an exception immediately?
Most important to me is this piece of information:
rsa.CspKeyContainerInfo.HardwareDevice
Does somebody know any other way to access this info without popup dialogs if smart card is missing?
Edit:
The Windows Security dialog pops up at this line of code:
var rsa = cert.PrivateKey as RSACryptoServiceProvider;
There is no way to prevent the popup using this code. There are other approaches, for example using PCSC or Setting the PIN of a smartcard programmatically

Access PrivateKey in x509 certificate in windows certificate store marked non-exportable

I've managed to access the certificates collection and target the specific certificate by thumbprint. I can access all its properties, and its "HasPrivateKey" is set to true.
The "Exportable" in the CspKeyContainerInfo is marked as false.
When I do a PrivateKey.ToXmlString(false) meaning I do not get the key parameters but just the Modulus and Exponent its fine:
<RSAKeyValue>
<Modulus>4hjg1ibWXHIlH...ssmlBfMAListzrgk=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
but if I set it to toXmlString(true) to get all the values it fails:
<RSAKeyValue>
<Modulus>4hjg1ibWXHIlH...ssmlBfMAListzrgk=</Modulus>
<Exponent>AQAB</Exponent>
<P>8QZCtrmJcr9uW7VRex+diH...jLHV5StmuBs1+vZZAQ==</P>
<Q>8CUvJTv...yeDszMWNCQ==</Q>
<DP>elh2Nv...cygE3657AQ==</DP>
<DQ>MBUh5XC...+PfiMfX0EQ==</DQ>
<InverseQ>oxvsj4WCbQ....LyjggXg==</InverseQ>
<D>KrhmqzAVasx...uxQ5VGZmZ6yOAE=</D>
</RSAKeyValue>
However if I re-import the certificate and mark it "Exportable", then the above gives me access to all the KeyInformation I need to proceed.
Is there a way to keep a key Non-Exportable, and still access the information with toXmlString(true) programatically by using x509....Certiificate2 object?
X509Certificate2Collection xcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByThumbprint, "4678237245FEDC8059D113675955DFB870D36BF4", false);
foreach (X509Certificate2 x509 in xcollection)
{
var y = x509.PrivateKey.ToXmlString(false);
var f = x509.PrivateKey.ToXmlString(true);
}
Cheers

.NET Use BouncyCastle to read ECC Certificate from Windows Store

I have generate some ECC Certificate using OpenSSL. I can see these certificates in windows store.
What I want to do is to load an ECC certificate, get its private key, public key to use in other encryption method, like:
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite | OpenFlags.OpenExistingOnly);
X509Certificate2Collection x509Certificate2Collection =
store.Certificates.Find(X509FindType.FindBySerialNumber, "008B2D89B2A75EE891", false);
X509Certificate2 cert= x509Certificate2Collection[0];
(use Bouncy Castle to read it here)
I also try with:
var asymmetricCipherKeyPair =
DotNetUtilities.GetKeyPair(x509Certificate2.PrivateKey);
But this give an Exception:
{"The certificate key algorithm is not supported."} System.Exception {System.NotSupportedException}

Setting permissions on private key for a certificate using code

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.

How to obtain CN of the certificates in particular store?

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.

Categories

Resources