01.02.2006 21:06:36ошибка получения PRIVATEKEYBLOB Ответов: 3
Victor Y. Sklyar
Не могу решить следующую задачу:

есть PEM в котором сертификат и секретный ключ.
c помощью openssl делаю из него PFX.
Программно импортирую PFX во временное хранилище с флагом CRYPT_MACHINE_KEYSET и с помощью CertAddCertificateContextToStore добавляю единственный сертификат в "MY" с флагом CERT_SYSTEM_STORE_LOCAL_MACHINE.

Теперь ставлю себе обратную задачу: получить PEM (причем только закрытого ключа).

Открываю хранилище "MY" c флагом CERT_SYSTEM_STORE_LOCAL_MACHINE, получаю контекст установленного сертификата.
Получаю для него CRYPT_KEY_PROV_INFO.
Запрашиваю для этой структуры провайдела с помощью CryptAcquireContext.
Получаю ключ AT_KEYEXCHANGE с помощью CryptGetUserKey.

Пытаюсь получить PRIVATEKEYBLOB с помощью CryptExportKey, но как результат ошибка
Key not valid for use in specified state

Как же импортировать приватный ключ? Где ошибка в моих действиях?



Key not valid for use in specified state.
 
Ответы:
02.02.2006 9:55:08Kirill Sobolev
Когда программно импортируете, надо также указывать флаг CRYPT_EXPORTABLE, ибо
If this flag is not used, calls to the CryptExportKey function with the key handle fail.
02.02.2006 12:28:28Victor Y. Sklyar
да действительно импортируется, но после преобразование в PEM он не такой как оригинальный... может я неправильное его преобразовываю?

так привожу к PFX

openssl openssl pkcs12 -export -in file.pem -out file.fpx -passout pass:

так устанавливаю сертификат с секретным ключем

CRYPT_DATA_BLOB blob; //заполнен данными из файла
HCERTSTORE hCetrStorePfx = ::PFXImportCertStore(&blob, L"", CRYPT_EXPORTABLE);
HCERTSTORE hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY");
PCCERT_CONTEXT pCertContext = ::CertEnumCertificatesInStore(hCetrStorePfx, NULL);
::CertAddCertificateContextToStore(hCertStore, pCertContext, CERT_STORE_ADD_ALWAYS, NULL);

так импортирую секретный ключ

HCERTSTORE hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY");
PCCERT_CONTEXT pCertContext = ::CertEnumCertificatesInStore(hCertStore, NULL); //он там один
DWORD cbData;
::CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbData);
CRYPT_KEY_PROV_INFO * pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO *)_alloca(cbData);
::CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, pCryptKeyProvInfo, &cbData);

HCRYPTPROV hProv;
::CryptAcquireContextW(&hProv, pCryptKeyProvInfo->pwszContainerName, pCryptKeyProvInfo->pwszProvName, pCryptKeyProvInfo->dwProvType, CRYPT_MACHINE_KEYSET);
HCRYPTKEY hKey;
::CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKey);

DWORD dwDataLen;
::CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwDataLen);
BYTE * pb = (BYTE *)_alloca(dwDataLen);
::CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pb, &dwDataLen);

DWORD cb;
base64hdr_encode(&Base64PrivateKeyHdrs, pb, dwDataLen, NULL, &cb);
BYTE * p = (BYTE *)_alloca(cb);
base64hdr_encode(&Base64PrivateKeyHdrs, pb, dwDataLen, p, &cb);

ofstream filePem("private_key.pem");
filePem.write((const char*)p, cb);
filePem.close();
02.02.2006 15:28:27Kirill Sobolev
Может быть.
А если экспорт сделать через PFXExportCertStoreEx а потом через openssl преобразовать в PEM - получится то что надо?