3

I'm trying to export certificate to pfx file. Here's what I do (simplified):

h = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL); 
p = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                  CertBlob.pbData, CertBlob.cbData);
CertSetCertificateContextProperty(p, CERT_KEY_PROV_HANDLE_PROP_ID, 0, &hPrivKey);
CertAddCertificateContextToStore(h, p, CERT_STORE_ADD_ALWAYS, NULL);
PFXExportCertStoreEx(h, &SomeBlob, L"", NULL, EXPORT_PRIVATE_KEYS);

PFX created, no private key exported. Anyone ever exported private key to pfx? What's the proper way to attach private key to certificate so that it could be exported?

Emerick Rogul
  • 6,706
  • 3
  • 32
  • 39
galets
  • 17,802
  • 19
  • 72
  • 101

2 Answers2

4

Apparently, CertSetCertificateContextProperty(p, CERT_KEY_PROV_HANDLE_PROP_ID ...)

is not good. Need to do this instead:

CRYPT_KEY_PROV_INFO kpi;
ZeroMemory( & kpi, sizeof(kpi) );
kpi.pwszContainerName = "my-container-name";
kpi.dwProvType = PROV_RSA_FULL;
kpi.dwKeySpec = AT_KEYEXCHANGE;
kpi.dwFlags = CRYPT_MACHINE_KEYSET;
CertSetCertificateContextProperty( pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, & kpi);

It's critical that provider name and other crap match the information that was used to generate actual key. It's not needed to set provider handle or any of that stuff. It also must be done before CertAddCertificateContextToStore.

This is the only way that I found to attach private key to a certificate.

galets
  • 17,802
  • 19
  • 72
  • 101
  • This really helped me. But when i import a third party CA issued PFX using PFXImportCertStore, the key gets automatically mapped to AT_KEYEXCHANGE rather than AT_SIGNATURE-, As this certificate's key usage indicates it is for digital signing, key encipherment etc, Have you overcome any such issues? Thanks – Raj Jun 11 '11 at 10:14
  • @Raj, sorry, I don't remember if I did and how... It was awhile ago, I apologise – galets Oct 24 '11 at 22:32
  • thanks a lot! I was searching for a solution for a whole day! – Michael Siebert Apr 18 '13 at 13:55
0

For the posterity:

The problem is related to the CertAddCertificateContextToStore call. Indeed, it does not copy the CERT_KEY_PROV_HANDLE_PROP_ID property to the next context. (this fact is noted in the remark)

Solution:

Fill the last parameter with a handle to the new context and copy the property from the old context to the next one.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • can you elaborate on this? how do you copy the property to the new context? Why does setting not work? Thanks. – stu Sep 17 '18 at 17:44