Saving/Restoring certs with MS CryptoAPI invalidat

2019-02-11 08:52发布

问题:

I've written a program which is supposed to save and restore a users certificates using the windows Crypto API. I was under the impression that it was working fine but now a user has complained that the private key that was attached to the certificate is invalid after the cert has been restored.

I was saving the certificates using:

HCERTSTORE hCertStore =
    CertOpenStore(CERT_STORE_PROV_PHYSICAL_W,
    0,
    NULL,
    CERT_SYSTEM_STORE_CURRENT_USER |
    CERT_STORE_OPEN_EXISTING_FLAG |
    CERT_STORE_READONLY_FLAG |
    CERT_STORE_UPDATE_KEYID_FLAG,
    (PVOID) storeName.c_str());

And then later:

if (!CertSaveStore(hCertStore,
    0,
    CERT_STORE_SAVE_AS_STORE,
    CERT_STORE_SAVE_TO_FILENAME,
    (PVOID) saveFile.c_str(),
    0))

I understand that the CERT_STORE_SAVE_AS_STORE flag should mean that the entire cert should get serialized including the private key. Although I note that MSDN says:

"The CERT_KEY_CONTEXT_PROP_ID property and the related CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_SPEC_PROP_ID values are not saved to a serialized store."

..which I confess, I don't really understand.

When I restore the cert I use CertFindCertificateInStore() to see if the cert is already present and only if it isn't I do:

bOK = CertAddCertificateContextToStore(
    hDestinationStore,
    pCertContext,
    CERT_STORE_ADD_USE_EXISTING,
    NULL);

To add the certificate back... So my question is, why might the private key not be preserved? Am I missing something?

回答1:

You use wrong CryptoAPI. You should use PFXExportCertStoreEx and PFXImportCertStore instead.

UPDATED: The functions are very common. You can not export certificates from the SmartCard of course or other non-exportable certificates. The BLOG in the function is nothing more as the contain of the PFX file. For example the import of the certificate from PFX file should do the following:

  1. Open the PFX file and read full contain in the memory. You can use of course the file mapping instead.
  2. Optionally you can use PFXIsPFXBlob function to verify that the file has really contain which corresponds to the PFX file.
  3. You use PFXImportCertStore to open the BLOB (the PFX) as the source certificate store.
  4. You use CertOpenStore or some other function to open the destination certificate store where you want save the certificates from the PFX file.
  5. You use CertEnumCertificatesInStore to enumerate certificates from the source certificate store (PFX) and for all certificate use CertAddCertificateContextToStore to add certificate from the source certificate store to the destination certificate store. The certificates having private key will be imported with the private key.
  6. You use CertCloseStore to close both opened stores.