1

I tried to export private key from certificate store by CNG API. It work fine when export RSA private key, but failed in EC private key.

The code failed in NCryptExportKey() with 0x80090029.

Is there any document from MS said: Export EC private key not support? or any sample code?

Here is my code:

    NCRYPT_KEY_HANDLE       hKey = NULL;
    SECURITY_STATUS         secStatus = ERROR_SUCCESS;
    NTSTATUS                status = STATUS_UNSUCCESSFUL;
    DWORD                   dwKeySpec, cbData = 0, cbBlob = 0, KeyPolicy = 0;
    PBYTE                   pbHash = NULL, pbBlob = NULL;
    PCCERT_CONTEXT          pSignerCert = NULL;
    unsigned char           *MessagePrivKey;
    Struct_Return ExportMessage = { NULL, 0 };
    bool bStatus;

    pSignerCert = GetCert(MY_CERT_NAME);

    if (!CryptAcquireCertificatePrivateKey(
        pSignerCert,
        CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG,
        NULL,
        &hKey,
        &dwKeySpec,
        NULL))
    {
        goto End;
    }

    if (FAILED(secStatus = NCryptExportKey(
        hKey,
        NULL,
        NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
        NULL,
        NULL,
        0,
        &cbBlob,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
        goto End;
    }

    pbBlob = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlob);
    if (NULL == pbBlob)
    {
        wprintf(L"**** memory allocation failed\n");
        goto End;
    }


    if (FAILED(secStatus = NCryptExportKey(
        hKey,
        NULL,
        NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
        NULL,
        pbBlob,
        cbBlob,
        &cbBlob,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
        goto End;
    }

I also tried to call NCryptSetProperty() before export, but it failed with 0x8009000b.

KeyPolicy =  NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG | NCRYPT_ALLOW_EXPORT_FLAG;

    if (FAILED(secStatus = NCryptSetProperty(
        hKey,
        NCRYPT_EXPORT_POLICY_PROPERTY,
        (PBYTE)&KeyPolicy,
        sizeof(KeyPolicy),
        NCRYPT_PERSIST_FLAG)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptSetProperty\n", secStatus);
        goto End;
    }
Assam
  • 179
  • 1
  • 13
  • maybe... https://mywindowshub.com/how-to-deal-with-tpm-issues-on-windows-hello-pin-generation-error/ – Woodstock Apr 07 '20 at 08:27
  • hmm...I need to export EC private key from certificate store. – Assam Apr 07 '20 at 08:50
  • 1
    May be due to the value of `NCRYPT_EXPORT_POLICY_PROPERTY`. To my knowledge, when an ECC key is created with `NCryptCreatePersistedKey`, the `NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG` must be set to allow an export of the private ECC key. This is probably the same for already stored keys. – Topaco Apr 07 '20 at 17:43
  • Hi Topaco, I also tried to call ```NCryptSetProperty()``` before export, but it failed with ```0x8009000b```. I added the code in the post. – Assam Apr 08 '20 at 01:14
  • The flag can only be set when the key is generated (e.g. with `NCryptCreatePersistedKey`) or imported (e.g. with `NCryptImportKey`), i.e. at this point it's too late (`0x8009000b` means `NTE_BAD_KEY_STATE: Key not valid for use in specified state`, because the generation/import is already finalized). My point was that the key to be exported probably does _not_ have the `NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG` flag (`0x02`) set for the `NCRYPT_EXPORT_POLICY_PROPERTY` property, but either none at all (`0x00`) or only `NCRYPT_ALLOW_EXPORT_FLAG` (`0x01`). This can be checked with `NCryptGetProperty`. – Topaco Apr 08 '20 at 06:54
  • Hi Topaco, I called ```NCryptGetProperty``` to get ```NCRYPT_EXPORT_POLICY_PROPERTY```, and it returned 0x04. But it also returned 0x04 with RSA key cert. The RSA private key can be exported. Do you know why? – Assam Apr 08 '20 at 07:50
  • `0x04` corresponds to `NCRYPT_ALLOW_ARCHIVING_FLAG`. Are you sure this is the contents of the buffer and not its size? In my tests, ECC and RSA keys behave identically concerning the flags. For an export (as plaintext) `NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG` must be set. `NCRYPT_ALLOW_EXPORT_FLAG`, or `NCRYPT_ALLOW_ARCHIVING_FLAG` (alone or together) are not sufficient. – Topaco Apr 08 '20 at 09:01
  • 1
    To bring the discussion to a close. Set the `NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG` during generation / import of the key. If your process doesn't allow this or the property is already set, you might be interested in this [link](https://stackoverflow.com/a/57330499), which is answered in the context of C#, but should in principle also be possible with C++. However, it's a bit elaborate: The key must be exported in encrypted form (for this `NCRYPT_ALLOW_EXPORT_FLAG` is sufficient) and can then be re-imported, whereby `NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG` can be set. – Topaco Apr 08 '20 at 09:58
  • Thanks for your link. I think I should export in encrypted form. I tried to set second parameter in ```NCryptExportKey()```, but failed. Do you know how to generate cryptographic key? RSA key or symmetric key? – Assam Apr 09 '20 at 07:00
  • I forgot to say, I called ```NCryptSetProperty()``` in right way, the ec cert return 0x01, RSA cert return 0x03. so ...you are right. Thanks – Assam Apr 09 '20 at 07:03
  • Hi Topaco, GOOD NEWS. I tried to export cert as pfx format by ```PFXExportCertStoreEx``` and import by ```PFXImportCertStore``` and set property. Then export EC private key!! You help me a lot! Please left your answer!! – Assam Apr 09 '20 at 08:57

0 Answers0