14.02.2003 13:47:57Программная установка клиентского сертификата Ответов: 4
Александр
После установки клиентского сертификата посредством вызова функций Crypto API и привязки сертификата к ключу на дискете (CryptSetKeyParam), при попытке установить соединение по SSL запрашивается диалог вставки ключевого носителя, после вставки выдается сообщение "Набор ключей не существует".
Если с этого же носителя установить сертификат в личное хранилище, используя панель управления CryptoPro, все работает нормально. Подскажите, может есть какая-то секретная функция, которую еще нужно дополнительно вызывать?

Вот последовательность вызовов, осуществляемая при программной установке сертификата в личное хранилище клиента, что здесь упущено?

HCRYPTPROV hProv = NULL;

if (CryptAcquireContext(&hProv, szContainerName, CP_DEF_PROV_A, PROV_GOST_DH, 0)) {
HCRYPTKEY hKeySig = NULL;

if (CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKeySig)) {
DWORD dwNameLength = 0;
DWORD dwProvLength = 0;
DWORD dwUserCertLength = 0;
DWORD dwOpenStore = CERT_SYSTEM_STORE_CURRENT_USER;
CRYPT_KEY_PROV_INFO provInfoSig = {0};

if (CryptGetProvParam(hProv, PP_UNIQUE_CONTAINER, NULL, &dwNameLength, 0))
CryptGetProvParam(hProv, PP_UNIQUE_CONTAINER, (BYTE*)provInfoSig.pwszContainerName, &dwNameLength, 0);

if (CryptGetProvParam(hProv, PP_NAME, NULL, &dwProvLength, 0))
CryptGetProvParam(hProv, PP_NAME, (BYTE*)provInfoSig.pwszProvName, &dwProvLength, 0);

provInfoSig.dwFlags = 0;
provInfoSig.dwKeySpec = AT_KEYEXCHANGE;
DWORD pdw = sizeof(provInfoSig.dwProvType);
CryptGetProvParam(hProv, PP_PROVTYPE, (BYTE*)&provInfoSig.dwProvType, &pdw, 0);

if (CryptGetKeyParam(hKeySig, KP_CERTIFICATE, NULL, &dwUserCertLength, 0)) {
BYTE *pbUserCert = (LPBYTE)malloc(dwUserCertLength);
PCCERT_CONTEXT pUserCert = NULL;
HANDLE hCertStore = 0;

if (CryptGetKeyParam(hKeySig, KP_CERTIFICATE, pbUserCert, &dwUserCertLength, 0)) {
pUserCert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pbUserCert, dwUserCertLength);

if (pUserCert) {
if (CertSetCertificateContextProperty(pUserCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provInfoSig)) {
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_STORE_OPEN_EXISTING_FLAG | dwOpenStore, L"MY");

if (hCertStore) {
if (CertAddCertificateContextToStore(hCertStore, pUserCert, /*CERT_STORE_ADD_USE_EXISTING*/CERT_STORE_ADD_REPLACE_EXISTING, NULL)) {
if (!CryptSetKeyParam(hKeySig, KP_CERTIFICATE, pUserCert->pbCertEncoded, 0))
MessageBox(GetErrorMessage(GetLastError()), _T("Ошибка привязки сертификата к ключу"), MB_OK | MB_ICONSTOP);
} // if !CertAddCertificateContextToStore
else
MessageBox(GetErrorMessage(GetLastError()), _T("Ошибка установки сертификата"), MB_OK | MB_ICONSTOP);
} // if hCertStore
} // if CertSetCertificateContextProperty
} // if pUserCert
} // if CryptGetKeyParam 2

if (hCertStore) CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
if (pUserCert) CertFreeCertificateContext(pUserCert);
if (pbUserCert) free(pbUserCert);
} // if CryptGetKeyParam 1
} // if CryptGetUserKey
else
MessageBox(GetErrorMessage(GetLastError()), _T("Ошибка открытия ключа"), MB_OK | MB_ICONSTOP);

if (hKeySig) CryptDestroyKey(hKeySig);
} // if CryptAcquireContext
if (hProv) CryptReleaseContext(hProv, 0);

Заранее благодарен.
 
Ответы:
14.02.2003 17:24:32kure
Функция не секретная.
Нужно заполнить структуру CRYPT_KEY_PROV_INFO и попользовать функцию CertSetCertificateContextProperty.
Пример у нас в файле property.c
14.02.2003 17:30:12Александр
Большое спасибо за ответ!
18.02.2003 16:28:45Александр
Однако, использование этой функции
CertSetCertificateContextProperty(pUserCert, CERT_KEY_PROV_INFO_PROP_ID, CERT_STORE_NO_CRYPT_RELEASE_FLAG, &provInfo) с предварительной установкой
provInfo.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID как написано в property.c не привела к разрешению проблемы, по прежнему сертификат устанавливается корректно, привязывается к ключу, но при работе клиента выдается ошибка "Набор ключей не существует", хотелось бы получить подробные разъяснения по этому вопросу или ссылку на документацию, где подобная проблема описана???!
18.02.2003 17:53:11kure
Скорее всего вы делаете не то.
Вы устанавливаете флаг кеширования ключа. А нужно сделать ссылку на секретный ключ.

Описание функции:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/certsetcertificatecontextproperty.asp

Описание структуры:
typedef struct _CRYPT_KEY_PROV_INFO { LPWSTR pwszContainerName;
LPWSTR pwszProvName;
DWORD dwProvType;
DWORD dwFlags;
DWORD cProvParam; PCRYPT_KEY_PROV_PARAM rgProvParam; DWORD dwKeySpec;
} CRYPT_KEY_PROV_INFO, *PCRYPT_KEY_PROV_INFO;

Заполните структуру:
имя ключевого контейнера, имя и тип провайдера.