runtime: Cannot export certificate data even with X509KeyStorageFlags.Exportable

If I export an X509Certificate2 using

var myCert = p_certificate.Export(X509ContentType.Pkcs12, SomeSecureString);

then save that to a file using

File.WriteAllBytes(filePath, myCert);

if I then create a new X509Certificate2 object

var newCert = new X509Certificate2(p_keyFilePath, p_keyFilePassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);

and try to export the private key

var loadedRsa = newCert.GetRSAPrivateKey(); var loadedPrivate = loadedRsa.ExportRSAPrivateKey();

I get

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException : The requested operation is not supported.

Any ideas or workarounds would be much appreciated.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 17 (11 by maintainers)

Most upvoted comments

@vcsjones Yours has the advantage of compiling, though. 6 seconds well spent 😉

Aw, lost by 6 seconds.

@SCLDGit

I can reproduce this with my own PFX now, and I don’t think there is anything particular about the PFX that is the problem. Rather, it’s that when Windows exports a PFX, it includes CSP key ID. So when you re-import the certificate, it gets that key handle.

I wonder then, if this works for you?

var exported = loadedRsa.ExportEncryptedPkcs8PrivateKey("temp", new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.SHA1, 1));
RSA temp = RSA.Create();
temp.ImportEncryptedPkcs8PrivateKey("temp", exported, out _);
var loadedPrivate = temp.ExportRSAPrivateKey();

Basically, do an indirect export through an encrypted export, first. What I think has happened is that your RSA key in CNG is marked as Exportable but not PlaintextExportable.

Just said it at https://github.com/dotnet/runtime/issues/26031#issuecomment-632912957, but here it is again in a different context:

Exportable ends up meaning two different things depending on if the key got loaded into Windows CAPI or Windows CNG. For CAPI it means … exportable – ExportParameters will work, and exporting as a PFX will work. For CNG it ends up meaning “exportable if encrypted”, so PFX export works, and ExportEncryptedPkcs8PrivateKey works… but ExportParameters and ExportPkcs8PrivateKey do not.

One work-around is to do something like

using (RSA tmp = RSA.Create())
using (RSA key = cert.GetRSAPrivateKey())
{
    PbeParameters pbeParameters = ...;
    tmp.ImportPkcs8PrivateKey(key.ExportPkcs8PrivateKey(pwd, pbeParameters), pwd);
    return tmp.ExportRSAPrivateKey();
}

We -could- do something like that in the platform when we get an error, but we’ve thus far resisted doing it.