.NET Framework x509Certificate2 Class, HasPrivateKey == true && PrivateKey == null? .NET Framework x509Certificate2 Class, HasPrivateKey == true && PrivateKey == null? powershell powershell

.NET Framework x509Certificate2 Class, HasPrivateKey == true && PrivateKey == null?


This may indicate one of the following:

1) the private key is stored in the Key Storage Provider (rather than legacy crypto service provider) which is poorly supported by .NET and not supported by PrivateKey property of X509Certificate2 class at all. You can check this by running the following command:

certutil -user -store my "<CertSerialNumber>"

2) the private key is missing.

HasPrivateKey property doesn't necessary reflect the actual picture and may True for non-existent keys or False for existing keys. Run the certutil command above to make sure if the key is presented.

In the case if private key is presented, but the bindings are broken, you can try to restore bindings by running the following command:

certutil -user -repairstore my "<CertSerialNumber>"


Your certutil information shows Provider = Microsoft Software Key Storage Provider which means that the private key is stored under Windows CNG, instead of Windows CryptoAPI (CAPI).

.NET 4.6 added the GetRSAPrivateKey (extension) method to facilitate the otherwise breaking change of letting the PrivateKey property return something which was not an RSACryptoServiceProvider (or DSACryptoServiceProvider). If you have access to that method (I'm not sure what version of the framework PowerShell uses) then it would solve your problem.

Two things to be aware of, though:

  1. GetRSAPrivateKey returns a unique Disposable object each time. You should put it in a using statement/manually call Dispose when finished with it (as opposed to cert.PrivateKey, which isn't unique, so shouldn't be Disposed).
  2. The sign/verify//encrypt/decrypt methods have moved down to the RSA base class (albiet with slightly different, more forward-looking, signatures).


I resolved the problem.

For some reason, .NET framework can't import private keys from files, however, it can import from the built-in windows store, this is because the PrivateKey method only supports RSA and DSA keys are per the Microsoft Spec: read the notes under "Remarks" section.

Anyhow, to get a PrivateKey object to return the key info, You need to do the following:

1) Import your P12 file into the Windows Keystore by double-clicking it.2) Select "Import" when prompted into "Current User"3) Make sure you select "Make Key Exportable",

if this option is not available then your certificate has no private key

. 4) Select "Automatically place into store"

5) Write the following code to retrieve your certificate:

Dim CertDataInfo As System.Security.Cryptography.X509Certificates.X509Certificate2 Dim Store As New System.Security.Cryptography.X509Certificates.X509Store("MY", Security.Cryptography.X509Certificates.StoreLocation.CurrentUser)Store.Open(Security.Cryptography.X509Certificates.OpenFlags.ReadOnly)Console.writeline (Store.Certificates.Count)For I = 0 To Store.Certificates.Count - 1 If Store.Certificates.Item(I).FriendlyName = "Heider Sati's Cert(48F57XTHVE)" Then  CertDataInfo = Store.Certificates.Item(I) End If Console.writeline ("Cert: " & Store.Certificates.Item(I).FriendlyName)NextStore.Close()If CertDataInfo.PrivateKey Is Nothing Then MsgBox("NULL")Else MsgBox("YES")End If

6) Run the code, if you get a YES then the private key is not NULL (or NOTHING), which is what you are looking for.

If you load the same certificate directly from the file, the Private key will always be NOTHING / NULL , but the HasPrivateKey will say YES, which means (I know there is a key, but yet, I don't know how to understand it. When you import it into the Windows store, then Windows does translate it into a .NET-Compatible format.

I hope this helps.