| ||||
| ||||
При программной установке сертификата в раздел "ЛИЧНЫЕ" они не отображаются если зайти IE->Свойства обозревателя->Сертификаты, хотя при запуске консоли mmc видно что они есть! При установке в "Другие пользователи", "Промежуточный центры" и "Доверенные корневые" отображаются исправно. Код установки: PCCERT_CONTEXT pUserCert = NULL; HANDLE hCertStore = 0; HANDLE hMyStore = 0; WideString L = "My"; hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, 0, CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L ); rv = CertAddEncodedCertificateToStore(hCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pBuffer, cBuffer, CERT_STORE_ADD_REPLACE_EXISTING|CERT_STORE_ADD_ALWAYS, NULL); Заранее благодарен за ответы! | ||||
Ответы: | ||||
| ||||
IE (а равно, Outlook, Outlook Express), как правило, не отображают те сертификаты из хранилища Личные, у которых нет ссылки на закрытый ключ. | ||||
| ||||
Но ключ то есть в реестре. Или надо как то явно ссылку указывать? | ||||
| ||||
Конечно, надо. Сама она не проставится :) CertSetCertificateContextProperty (...CERT_KEY_PROV_INFO_PROP_ID...). | ||||
| ||||
Спасибо, Василий! Сетификат в IE виден. Однако, при попытке зайти на сервер по защищенному соединению, IE закрывает соединение с сообщением "Не возможно отобразить страницу". Если установить этот же сертификат в личное хранилище, используя панель управления CryptoPro, все работает нормально. Т.е. ссылки на закрытый ключ нет или она как то "криво" проставилась??? Вот код: HCRYPTPROV hProv = NULL; HCRYPTKEY hKeySig = NULL; DWORD dwNameLength = 0; DWORD dwProvLength = 0; DWORD dwUserCertLength = 0; CRYPT_KEY_PROV_INFO provInfoSig = {0}; HANDLE hCertStore = 0; HANDLE hMyStore = 0; WideString L; DWORD cBuffer = 0; BYTE *pBuffer = NULL; BYTE *pbUserCert = NULL; CryptAcquireContext(&hProv, UserName, NULL, 75, 0); CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKeySig); CryptGetProvParam(hProv, PP_UNIQUE_CONTAINER, NULL, &dwNameLength, 0); provInfoSig.pwszContainerName = (wchar_t *)malloc(dwNameLength); CryptGetProvParam(hProv, PP_UNIQUE_CONTAINER, (BYTE*)provInfoSig.pwszContainerName, &dwNameLength, 0); CryptGetProvParam(hProv, PP_NAME, NULL, &dwProvLength, 0); provInfoSig.pwszProvName = (wchar_t *)malloc(dwProvLength); 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); CryptGetKeyParam(hKeySig, KP_CERTIFICATE, NULL, &dwUserCertLength, 0); pbUserCert = (LPBYTE)malloc(dwUserCertLength); CryptGetKeyParam(hKeySig, KP_CERTIFICATE, pbUserCert, &dwUserCertLength, 0); hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, 0, CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"My" ); .... // Считываем файл сертификата в буфер pBuffer ..... PCCERT_CONTEXT CertCont = NULL; CertCont = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pBuffer, cBuffer); CertSetCertificateContextProperty(CertCont, CERT_KEY_PROV_INFO_PROP_ID, 0, &provInfoSig); CertAddCertificateContextToStore(hCertStore, CertCont, /*CERT_STORE_ADD_USE_EXISTING*/ CERT_STORE_ADD_REPLACE_EXISTING, NULL); CryptSetKeyParam(hKeySig, KP_CERTIFICATE, CertCont->pbCertEncoded, 0); ... //Освобождение ..... Насколько я понял, собственно "привязка" сертификата к закрытому ключу производиться функцией CertSetCertificateContextProperty(CertCont, CERT_KEY_PROV_INFO_PROP_ID, 0, &provInfoSig); где например provInfoSig.pwszContainerName = "REGISTRY\\123456" или еще что то необходимо сделать? | ||||
| ||||
По поводу заполнения структуры CRYPT_KEY_PROV_INFO посмотрите в http://www.cryptopro.ru/CryptoPro/forum/view.asp?q=81 По-видимому, всё различие в том, что нужен UNICODE для имени контейнера и имени криптопровайдера. | ||||
| ||||
Извините, небольшая ошибочка вышла. Я немного неточно выразился. Имелось в виду (BYTE *)provInfoSig.pwszContainerName = "REGISTRY\\123456", а provInfoSig.pwszContainerName при трассировке естественно в UNICODE "\x4552\x4947 ..... и т.д." | ||||
| ||||
Поищите отличия с http://www.cryptopro.ru/cryptopro/forum/view.asp?q=2648 | ||||
| ||||
Отличия поискал.... но результат тот же. код: HCRYPTPROV hProv = NULL; HCRYPTKEY hKeySig = NULL; DWORD dwNameLength = 0; DWORD dwProvLength = 0; DWORD dwUserCertLength = 0; CRYPT_KEY_PROV_INFO provInfoSig = {0}; HCERTSTORE hCertStore = 0; WideString L = "MY"; DWORD cBuffer = 0; BYTE *pBuffer = NULL; BYTE *pbUserCert = NULL; // Инициализация контекста криптопровайдера if(!CryptAcquireContext(&hProv, UserName, NULL, 75, 0)) return ERR_NO_CONTEXT; // Получаем хендел на закрытый ключ rv = CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKeySig); // Получаем уникальное имя контейнера CryptGetProvParam(hProv, PP_UNIQUE_CONTAINER, NULL, &dwNameLength, 0); provInfoSig.pwszContainerName = (wchar_t *)malloc(dwNameLength); rv = CryptGetProvParam(hProv, PP_UNIQUE_CONTAINER, (BYTE *)provInfoSig.pwszContainerName, &dwNameLength, 0); // Получаем имя криптопровайдера CryptGetProvParam(hProv, PP_NAME, NULL, &dwProvLength, 0); provInfoSig.pwszProvName = (wchar_t *)malloc(dwProvLength); rv = CryptGetProvParam(hProv, PP_NAME,(BYTE *)provInfoSig.pwszProvName, &dwProvLength, 0); // устанавливаем флаги provInfoSig.dwFlags = 0; provInfoSig.dwKeySpec = AT_KEYEXCHANGE; // Получаем тип провайдера DWORD pdw = sizeof(provInfoSig.dwProvType); rv = CryptGetProvParam(hProv, PP_PROVTYPE, (BYTE*)&provInfoSig.dwProvType, &pdw, 0); .... // Считываем файл сертификата в буфер pBuffer ...... PCCERT_CONTEXT CertCont = NULL; PCCERT_CONTEXT pDesiredCert = NULL // Создаем контекст сертификата CertCont = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pBuffer, cBuffer); // Открываем хранилище hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L); // Добавляем сертификат в хранилище rv = CertAddCertificateContextToStore(hCertStore, CertCont, CERT_STORE_ADD_NEW, &pDesiredCert); // "Связываем" сертификат и закр. ключ rv = CertSetCertificateContextProperty(pDesiredCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provInfoSig); // Устанавливаем сертификат в контейнер закр. ключа rv = CryptSetKeyParam(hKeySig, KP_CERTIFICATE, CertCont->pbCertEncoded, 0); ... // Освобождение .... Мы тестируем TLS. Может при привязке к TLS следует осуществить еще какие то действия????? | ||||
| ||||
Нет, TLS использует обычным образом установленные сертификаты. Предлагаю сравнить: 1) установить сертификат через панель CSP (Сервис - Установить личный сертификат). Далее взять файл \Documents and Settings\<имя пользователя Win>\Application Data\Microsoft\SystemCertificates\My\Certificates\<Отпечаток> и переместить его в другую папку. (Отпечаток - это нижнее поле на вкладке Состав при просмотре сертификата в окошке) 2) установить сертификат Вашей программой, найти (там же) этот файл и сравнить. | ||||
| ||||
Файлы сравнил. Отличия как по размеру, так и по содержанию. При просмотре в текстовом режиме в файле, установленном с помощью панели управления CryptoPro присутствует такие строки: 扭癆叿눢ὼ㹋஫슡殭 ¼ D K REGISTRY\\87654321 Crypto-Pro GOST R 34.10-2001 Cryptographic Service Provider 䯟?昛袶㈘ୁž䕻眇 ҝ 舰餄舰䘄ΠĂȂ愊琂™ в файле установленном моей программой, вместо этого: 扭癆叿눢ὼ㹋஫슡殭 䯟?昛袶㈘ୁž䕻眇 \ 4 K 䕒䥇呓奒屜㜸㔶㌴ㄲ 牃灹潴倭潲䜠协⁔⁒㐳ㄮⴰ〲㄰䬠ㅃ䌠偓 ҝ 舰餄舰䘄ΠĂȂ愊琂™ т.е., насколько я понимаю, в наличие отсутствие связи сертификата с закр. ключом? Как же бороться то с этой бедой? | ||||
| ||||
Собственно, видно, что отличие в кодировке имени контейнера и имени криптопровайдера. | ||||