I have a certificate installed on my machine and when I go to view it, I see the message "You have a private key that corresponds to this certificate" however, when I try to access that private key in code, it is null. I use the following code to get my certificate:
var x509Certificate = GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=SomeCert");
Where:
public X509Certificate2 GetCertificate(string storeName, string storeLocation, string subjectName)
{
var store = new X509Store(getStoreName(storeName), getStoreLocation(storeLocation));
X509Certificate2Collection certificates = null;
store.Open(OpenFlags.ReadOnly);
try
{
X509Certificate2 result = null;
certificates = store.Certificates;
return getCertificateResult(certificates, subjectName, result);
}
finally
{
if (certificates != null)
{
foreach (var cert in certificates)
{
cert.Reset();
}
}
store.Close();
}
}
And:
private static X509Certificate2 getCertificateResult(IEnumerable certificates, string subjectName, X509Certificate2 result)
{
foreach (var cert in certificates.Cast<X509Certificate2>().Where(cert => cert.SubjectName.Name != null && cert.SubjectName.Name.ToLower() == subjectName.ToLower()))
{
if (result != null)
{
throw new ApplicationException(string.Format("There is more than one certificate found for subject Name {0}", subjectName));
}
result = new X509Certificate2(cert);
}
if (result == null)
{
throw new ApplicationException(string.Format("No certificate was found for subject Name {0}", subjectName));
}
return result;
}
I get my certificate back fine, however when I try to access the private key, doing the following:
x509Certificate.PrivateKey
The value for PrivateKey is null. What am I doing wrong? I need this value to sign a SAML2 request.
Note: I understand that I have some abstractions in there but the point is that I get the certificate back (it's found) but the private key is null. If there is any more information about my abstraction that is preventing the question from being answered, I can provide more detail.
As it's described here .cer
file (I guess it's also applicable to all certificate formats) can't contain private key. And it looks correctly from security point of view because this file is public.
But X509Certificate2
is not just a certificate, it's a container for certificate itself and some other stuff. That's why it has property PrivateKey
. In case if you need this information in your code and if you have a private key file (.pvk
) and password - you can use .pfx
file instead of .cer
. It can be created using pvk2pfx
utility:
> MakeCert -r -pe -ss SampleStoreName -n "CN=Sample" Sample.cer -sky exchange -sv Sample.pvk
> pvk2pfx -pvk Sample.pvk -pi SamplePassword -spc Sample.cer -pfx Sample.pfx -f
The documentation for Reset states that it frees the certificate's resources. Of course, because the method is called Reset and not Dispose, it's a reasonable assumption that the instance should be able to reacquire those resources if they are needed again later. Unfortunately that's not the case.
In the finally block of GetCertificate, you call Reset on every certificate in the collection - including the one you're returning, which makes it useless.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With