rism
rism

Reputation: 12142

X509 certificate imported from certificate store has no private key

There's some simple code to import a certificate with a private key into the Windows Certificate store using .net core 2.2:

  using (var store = new X509Store(StoreName.Root,StoreLocation.CurrentUser))
  {
      store.Open(OpenFlags.ReadWrite);
      store.Add(cert);
      store.Close();
  }

And some just as simple code to read it back out again:

 using (var store = new X509Store(StoreName.Root,StoreLocation.CurrentUser))
 {
    store.Open(OpenFlags.ReadOnly);
    var certCollection = store.Certificates.Find(X509FindType.FindBySubjectName, commonName, validOnly);
    store.Close();
    return certCollection;
 }

However although the certificate is successfully retrieved into the certCollection, it's private key is null and hasPrivateKey is false, even though they were not null and true on the prior Add call. Why is this?

Update:

using (RSA rsa = RSA.Create(keySize)) {    
     CertificateRequest certRequest = new CertificateRequest(
         subjectName,
         rsa,
         HashAlgorithmName.SHA512,
         RSASignaturePadding.Pkcs1);

     certRequest.CertificateExtensions
         .Add(newX509SubjectKeyIdentifierExtension(certRequest.PublicKey, false));  
     return certRequest;
}

Upvotes: 5

Views: 5197

Answers (2)

Bob-HL
Bob-HL

Reputation: 56

X509Certificate2 cert = new X509Certificate2("a.pfx", "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(xCertificate);

Cause When the certificate is installed by using the X509Certificate or X509Certificate2 class, X509Certificate or X509Certificate2 by default creates a temporary container to import the private key. The private key is deleted when there's no longer a reference to the private key.

Resolution To create a permanent key container for the private key, the X509KeyStorageFlags.PersistKeySet flag must be used to prevent .NET from deleting the key container. The following code should be used instead.

Ref: https://learn.microsoft.com/en-us/troubleshoot/developer/dotnet/framework/general/install-pfx-file-using-x509certificate

Upvotes: 1

bartonjs
bartonjs

Reputation: 33256

Your key is being created as an ephemeral key, so when it's being added to a persisted store the key is being discarded.

If you want to persist the key into the store certificate, you either need to create it as a persisted key directly, or export to a PFX then re-import (which is the easiest form):

// If you're planning on saving to a LocalMachine store you should also | in the
// X509KeyStorageFlags.MachineKeySet bit.
X509KeyStorageFlags storageFlags = X509KeyStorageFlags.PersistKeySet;

X509Certificate2 certWithPersistedKey =
    new X509Certificate2(
        certWithEphemeralKey.Export(X509ContentType.Pkcs12, ""),
        "",
        storageFlags);

Now certWithPersistedKey can be added like you expect.

Upvotes: 8

Related Questions