Статус: Участник
Группы: Участники
Зарегистрирован: 24.01.2008(UTC) Сообщений: 16  Откуда: Москва
|
Добрый день. Опишу проблему. Клиенту был выписан сертификат (Key Usage: Signature). Далее этот сертификат был установлен через браузер. После чего при открытии этого сертификата в консоли mmc можно было видеть, что у него есть личный ключ, и этот сертификат можно было без вопросов экспортировать в файл. Была написана программка для экспорта закрытого ключа сертификата. Ключи были выгружены в файл, а контейнер был удален при помощи утилиты администрирования КриптоПро (в Панели Инструментов). Далее была написана еще одна программа для импорта этих файлов (сертификата и закрытого ключа) в систему. Сертификат добавляется, ключ привязывается, но теперь при открытии сертификата при экспорте его в файл выдается окно с запросом на выбор ключевого носителя с неудобоваримым названием. Я так понимаю, что требуется выбрать носитель, в котором были первоначально сгенерированы ключи? Возможно ли обойти данный запрос? Далее. При попытке подписать какие-либо данные данным сертификатом выдается ошибка NTE_KEYSET_NOT_DEF. Как задать контейнер для ключа сертификата? Как делался экспорт закрытого ключа Код:
// Открываем хранилище
hStore := CertOpenStore(CERT_STORE_PROV_SYSTEM, cnt_ENCODING_TYPE, 0, CERT_SYSTEM_STORE_CURRENT_USER, 'MY');
// Берем нужный нам сертификат
pCert := CrpGetCertContext(hStore, IssuerName, CertSerial);
// Берем провайдера относящегося к сертификату
CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, nil, ProvInfoSize);
pProvInfo := PCRYPT_KEY_PROV_INFO(AllocMem(ProvInfoSize));
CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, pProvInfo, ProvInfoSize);
CryptAcquireContext(hProv, PAnsiChar(WideCharToString(pProvInfo.pwszContainerName)), nil, pProvInfo.dwProvType, 0);
// получаем ключ, который будем экспортировать
CryptGetUserKey(hProv, AT_SIGNATURE, hUserKey);
// на основании пароля создаем ключ обмена, на котором будет экспортироваться искомая ключевая пара
CryptCreateHash(hProv, CALG_GR3411, 0, 0, hHash);
CryptHashData(hHash, PByte(KeyPassword), StrLen(KeyPassword), 0);
CryptDeriveKey(hProv, CALG_G28147, hHash, CRYPT_EXPORTABLE, hSessionKey);
// экспортируем ключи
algid_export := CALG_PRO_EXPORT;
CryptSetKeyParam(hSessionKey, KP_ALGID, @algid_export, 0);
CryptExportKey(hUserKey, hSessionKey, PRIVATEKEYBLOB, 0, nil, KeyBufLen);
KeyBuf := AllocMem(KeyBufLen);
CryptExportKey(hUserKey, hSessionKey, PRIVATEKEYBLOB, 0, KeyBuf, KeyBufLen);
// Далее чистим ресурсы
// Всё
Как проводился импорт сертификата и ключа Код:
// получим контекст сертификата
pCert := CertCreateCertificateContext(X509_ASN_ENCODING, CertData, CertDataLen);
// открываем хранилище сертификатов MY (личное)
hStore := CertOpenStore(CERT_STORE_PROV_SYSTEM, cnt_ENCODING_TYPE, 0, CERT_SYSTEM_STORE_CURRENT_USER, 'MY');
// пробуем получить контейнер в реестре с именем mycontainer
if not CryptAcquireContext(hProv, 'mycontainer', nil, 75, CRYPT_SILENT) then
// если такого контейнера нет, то создаем его
if not CryptAcquireContext(hProv, 'mycontainer', nil, 75, CRYPT_NEWKEYSET) then
raise Exception.Create('Container error');
// зададим пароль на доступ к контейнеру
Buf := '12345678';
CryptSetProvParam(hProv, PP_SIGNATURE_PIN, PByte(Buf), 0);
// создаем ключ, на котором был зашифрована ключевая пара
CryptCreateHash(hProv, CALG_GR3411, 0, 0, hHash);
CryptHashData(hHash, PByte(KeyDataPassword), StrLen(KeyDataPassword), 0);
CryptDeriveKey(hProv, CALG_G28147, hHash, CRYPT_EXPORTABLE, hSessionKey);
// импортируем ключ в контейнер
algid_export := CALG_PRO_EXPORT;
CryptSetKeyParam(hSessionKey, KP_ALGID, @algid_export, 0);
CryptImportKey(hProv, KeyData, KeyDataLen, hSessionKey, 0, hKey);
// заполняем имя контейнера
provInfo.pwszContainerName := 'mycontainer';
// заполняем имя провайдера
provInfo.pwszProvName := CP_DEF_PROV; // 'Crypto-Pro Cryptographic Service Provider'
// заполняем тип провайдера
provInfo.dwProvType := PROV_GOST_DH; // 75
// устанавливаем привязку ключей к сертификату
provInfo.dwFlags := CERT_SET_KEY_PROV_HANDLE_PROP_ID;
provInfo.cProvParam := 0;
provInfo.rgProvParam := nil;
provInfo.dwKeySpec := AT_SIGNATURE;
CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, @provInfo);
// заносим сертификат в хранилище
CertAddCertificateContextToStore(hStore, pCert, CERT_STORE_ADD_ALWAYS, nil);
// очищаем ресурсы
// всё
|