Install a PFX file by using X509Certificate from a standard .NET application

This article helps you resolve exceptions when you install a PFX file by using X509Certificate from a standard .NET application.

Original product version:   .NET Framework
Original KB number:   950090

Symptom

A standard .NET application tries to install a certificate in a PFX file (PKCS12) programmatically by using the X509Certificate or X509Certificate2 class with code like the following example:

X509Certificate2 cert = new X509Certificate2("a.pfx", "password");
X509Store store = new X509Store(StoreName.My);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);

or

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

The following type of exception will occur when you try to use the certificate's private key within another application:

Unhandled Exception: System.Security.Cryptography.CryptographicException: Keyset does not exist
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at UseCertPrivateKey.Program.Main(String[] args) in C:\UseCertPrivateKey\Program.cs:line 20

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.

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

or

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);