13

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.

Brian David Berman
  • 7,514
  • 26
  • 77
  • 144

3 Answers3

7

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
Community
  • 1
  • 1
Dmitry
  • 452
  • 1
  • 3
  • 10
2

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.

Joe
  • 21
  • 2
  • that is clearly not the case. In the getCertificateResult method, he is clearly creating a new certificate instance and returning that. So it will have the proper details upon return. – Imran Rashid Mar 11 '14 at 09:38
0

I know the question is pretty old but for any future readers out there, let me add my thoughts.

To me it seems like that the certificate you are getting does not contain the private key. All the certificates in the stores do not have the private keys with them. Your own certificates will have the private keys, of course, but the certificates for other entities will not have the private keys which makes sense.

In your code you are not showing the store location you are getting certificates from. Could it be that the certificate you are getting is not one of your own?

Imran Rashid
  • 1,328
  • 14
  • 21