.NET Use BouncyCastle to read ECC Certificate from Windows Store - c#

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}

Related

Create a X509Certificate2 object using PEM with password in .NET Framework

I really don't understand how certificates work and can't find much information on how to create a X509Certificate2 object in .NET Framework. I need the certificate object so that I can add it to an Http handler. I have three items: a cert.pem file, a key.pem file and a password that I provided when I created the files. The files where generated from running this command:
> "C:\Program Files\Git\usr\bin\openssl.exe" req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365
The console then asked me to provide a "PEM pass phrase" and I entered it. Now I was able to create a X509Certificate2 object in .NET 6, but cannot find a way to do the same in .NET Framework.
This code works in .NET 6, but I have no idea how to do the same thing in .NET Framework 4.6.1.
public static X509Certificate2 CreateCertificate(string publicCert, string privateCert, string password = #"P#ssw0rd1")
{
byte[] publicPemBytes = Encoding.UTF8.GetBytes(publicCert);
using var publicX509 = new X509Certificate2(publicPemBytes);
var privateKeyBlocks = privateCert.Split("-", StringSplitOptions.RemoveEmptyEntries);
var privateKeyBytes = Convert.FromBase64String(privateKeyBlocks[1]);
RSA rsa = RSA.Create();
if (privateKeyBlocks[0] == "BEGIN ENCRYPTED PRIVATE KEY")
{
rsa.ImportFromEncryptedPem(privateCert, password);
}
X509Certificate2 keyPair = publicX509.CopyWithPrivateKey(rsa);
return keyPair;
}
The variable publicCert has the raw value of the cert.pem file (the one that start with -----BEGIN CERTIFICATE-----. The variable privateCert has the raw value of the key.pem file (the one that start with -----BEGIN ENCRYPTED PRIVATE KEY-----.

Smart Card gives null as a value of private key

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.

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

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