| ||||
| ||||
Добрый день, уважаемые, у меня такой вопрос: Создаю инсталляцию для пользователя, и крайне не хочется ему слать инструкцию по установке личного сертификата, связывания его с контейнером закрытых ключей и пр. Так вот собственно вопрос: Возможно ли установить личный сертификат из командной строки, если да, то как? | ||||
Ответы: | ||||
| ||||
http://cryptopro.ru/cryptopro/forum/view.asp?q=6567 | ||||
| ||||
Примного благодарен, а можно ли достать исходники этой замечательной проги (cryptCP) чтоб я в свою dllлину мог этот блок включить? | ||||
| ||||
Ответьте мне пожалуйста. Я запускаю вашу утилиту cryptCp и на любую комнду она мне отвечает, что лицензия просрочена вот пример D:\project\cryptCP>cryptcp.exe -CSPcert -df test2.cer -nochain -norev CryptCP 3.16 (c) "Крипто-Про", 2002-2006. Утилита командной строки для защиты данных. Ошибка: Лицензия просрочена. (0x20000325) При запуске КриптоПро написано "Время действия лицензии - постоянная" | ||||
| ||||
версия криптоПро КС1 3.0.3300.2 | ||||
| ||||
версия cryptCp 3.16 | ||||
| ||||
У КриптоПро CSP и cryptcp разные лицензии. Лицензия на cryptcp приобретается отдельно. У нас на сайте вместе с дистрибутивом cryptcp выложена лицензия для тестирования сроком на 30 дней. | ||||
| ||||
Штука платная, понял. Тогда такой вопрос, не могли бы Вы вложить кусок кода, который предлагает пользователю выбрать контейнер с приватным ключом и возвращал бы String имя этого контейнета для того, чтоб я мог добавить его в загружаемый сертификат таким образом CRYPT_KEY_PROV_INFO kpi; ZeroMemory(&kpi, sizeof(kpi)); kpi.pwszContainerName = pszKeyContainerName; kpi.pvParam = 0; kpi.rgProvParam = 0; wszProvName = NULL; kpi.dwProvType = PROV_RSA_FULL; kpi.dwFlags = 0; kpi.dwKeySpec = AT_SIGNATURE;// AT_KEYEXCHANGE; kpi.cPro if (!CertSetCertificateContextProperty(pCertContext,CERT_KEY_PROV_HANDLE_PROP_ID, 0, &kpi)) { CryptDestroyKey(hKeyUser); CryptReleaseContext(hCertProvUser, 0); } Возможно, что я глобально в чем-то ошибаюсь, ибо новичек. Поправьте, если что не так | ||||
| ||||
где pszKeyContainerName как раз полученное имя ключегого контейнера | ||||
| ||||
где pszKeyContainerName как раз полученное имя ключегого контейнера | ||||
| ||||
где pszKeyContainerName как раз полученное имя ключегого контейнера | ||||
| ||||
как я понял, почитав эту переписку: ------------------------------------------ Антон Ответить Спасибо за поправку. Но у меня вопрос: могу ли я с помощью API Crypto Pro получить информацию о считывателях ключевых носителей, которые использует Crypto Pro в данный момент (и получить информацию об ключевых контейнерах в ключевом носителе). Могу ли я с помощью вашего API получить пользовательский интерфейс наподобие интерфейса "Control Panel->Crypto Pro CSP->Service->View Certificates in container"? Ответы: 13.10.2003 10:04:41 Я сам (Антон) Ладно, я понял. Информацию о текущих считывателях ключевых контейнеров можно почерпнуть из реестра. Но как узнать какие ключевые контейнеры мне доступны (например, со смарт-карты)? 13.10.2003 10:28:16 uri По первому вопросу: API нету. :-( Нуно вашему софту лезть в реестр и в разделе HKEY_LOCAL_MACHINE\SOFTWARE\Crypto Pro\Cryptography\CurrentVersion\KeyDevices перечислены считыватели ключевых носителей. Если у раздела есть подраздел, то значит КриптоПро CSP настроен на него :-) А список ключевых контейнеров, доступных в системе можно посмотреть с помощью функции CPGetProvParam(), которая производит возвращение параметров криптопровайдера. Одним из параметров является PP_ENUMCONTAINERS. Посмотрите в руководстве программиста КриптоПро CSP ЖТЯИ.00005-01 90 03 подробнее. По второму вопросу: Посмотрите наш проект в качестве примера. а в нем csptest -property -cinstall. Возьмите за основу... --------------------------------------------- Понял, что готовой приблуды нет, запустив которую она выкинет окно с контейнерами и вернет наименование? | ||||
| ||||
В CSP есть, вылезет окно аналогичное тому, которое вылезает в контрольной панели - CryptGetProvParam(.., PP_SELECT_CONTAINER, ..) | ||||
| ||||
не поверите, но CryptGetProvParam не поддерживает параметр PP_SELECT_CONTAINER пишу такой код, на что мне выдается ошибка "Указан неправильный тип" вот код: HCRYPTPROV m_hCryptProv = NULL; if (!CryptAcquireContext(&m_hCryptProv, NULL, NULL, 75, 0)) { m_hCryptProv = NULL; THROW_GLE(); } // Петр 30.10.2007 DWORD szKeyContainerLen = 0; LPTSTR szKeyContainer = NULL; if (!CryptGetProvParam (m_hCryptProv, PP_SELECT_CONTAINER, NULL, &szKeyContainerLen, 0)) { THROW_ERR(_T("Ошибка при получении размера имени контейнера секретного ключа"), GetLastError()); } if (szKeyContainerLen <= 0){ THROW_ERR(_T("Не удалось получить имя контейнера секретного ключа"), GetLastError()); } szKeyContainer = (LPTSTR)ALLOC(szKeyContainerLen); if (!CryptGetProvParam (m_hCryptProv, PP_SELECT_CONTAINER, (LPBYTE)szKeyContainer, &szKeyContainerLen, 0)) { THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } | ||||
| ||||
А сам параметр у вас определен? #define PP_SELECT_CONTAINER 110 | ||||
| ||||
да пробовал и так. Все равно пишет, что "Указан неправильный тип." вот код, которым я пытаюсь это сделать Указан неправильный тип. | ||||
| ||||
вот код DWORD szKeyContainerLen = 0; LPTSTR szKeyContainer = NULL; if (!CryptGetProvParam (m_hCryptProv, 110, NULL, &szKeyContainerLen, 0)) { THROW_ERR(_T("Ошибка при получении размера имени контейнера секретного ключа"), GetLastError()); } if (szKeyContainerLen <= 0){ THROW_ERR(_T("Не удалось получить имя контейнера секретного ключа"), GetLastError()); } szKeyContainer = (LPTSTR)ALLOC(szKeyContainerLen); if (!CryptGetProvParam (m_hCryptProv, 110, (LPBYTE)szKeyContainer, &szKeyContainerLen, 0)) { THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } | ||||
| ||||
максимальную длину имени надо определять так CryptGetProvParam (m_hCryptProv, PP_ENUMCONTAINERS, NULL, &szKeyContainerLen, CRYPT_FIRST)) | ||||
| ||||
день добры, спасибо, контейнер выбирает... но к сертификату не привязывает закрытый ключ. помоему я что-то забыл сделать я делаю так. передаю в функцию контекст сертификата, получаю имя контейнера, добавляю его в сертификат через CertSetCertificateContextProperty и добавляю сертификат в хренилище. Что я пропустил? вот код всей моей функции { HCRYPTPROV m_hCryptProv = NULL; if (!CryptAcquireContext(&m_hCryptProv, NULL, NULL, 75, 0)) { m_hCryptProv = NULL; THROW_GLE(); } // Петр 30.10.2007 DWORD szKeyContainerLen = 0; LPTSTR szKeyContainer = NULL; if (!CryptGetProvParam (m_hCryptProv, PP_ENUMCONTAINERS, NULL, &szKeyContainerLen, CRYPT_FIRST)) { THROW_ERR(_T("Ошибка при получении размера имени контейнера секретного ключа"), GetLastError()); } if (szKeyContainerLen <= 0){ THROW_ERR(_T("Не удалось получить имя контейнера секретного ключа"), GetLastError()); } szKeyContainer = (LPTSTR)ALLOC(szKeyContainerLen); if (!CryptGetProvParam (m_hCryptProv, 110, (LPBYTE)szKeyContainer, &szKeyContainerLen, 0)) { THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } CRYPT_KEY_PROV_INFO kpi; ZeroMemory(&kpi, sizeof(kpi)); kpi.pwszContainerName = (LPWSTR)szKeyContainer; kpi.pwszProvName = NULL; kpi.dwProvType = PROV_RSA_FULL; kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; kpi.dwKeySpec = AT_KEYEXCHANGE; kpi.cProvParam = 0; kpi.rgProvParam = 0; if (!CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &kpi)) { THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } if (!CertAddCertificateContextToStore(m_hCertStore, pCert, CERT_STORE_ADD_REPLACE_EXISTING, NULL)){ THROW_ERR(_T("Ошибка при добавлении сертификата в личное хранилище"), GetLastError()); } | ||||
| ||||
день добры, спасибо, контейнер выбирает... но к сертификату не привязывает закрытый ключ. помоему я что-то забыл сделать я делаю так. передаю в функцию контекст сертификата, получаю имя контейнера, добавляю его в сертификат через CertSetCertificateContextProperty и добавляю сертификат в хренилище. Что я пропустил? вот код всей моей функции { HCRYPTPROV m_hCryptProv = NULL; if (!CryptAcquireContext(&m_hCryptProv, NULL, NULL, 75, 0)) { m_hCryptProv = NULL; THROW_GLE(); } // Петр 30.10.2007 DWORD szKeyContainerLen = 0; LPTSTR szKeyContainer = NULL; if (!CryptGetProvParam (m_hCryptProv, PP_ENUMCONTAINERS, NULL, &szKeyContainerLen, CRYPT_FIRST)) { THROW_ERR(_T("Ошибка при получении размера имени контейнера секретного ключа"), GetLastError()); } if (szKeyContainerLen <= 0){ THROW_ERR(_T("Не удалось получить имя контейнера секретного ключа"), GetLastError()); } szKeyContainer = (LPTSTR)ALLOC(szKeyContainerLen); if (!CryptGetProvParam (m_hCryptProv, 110, (LPBYTE)szKeyContainer, &szKeyContainerLen, 0)) { THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } CRYPT_KEY_PROV_INFO kpi; ZeroMemory(&kpi, sizeof(kpi)); kpi.pwszContainerName = (LPWSTR)szKeyContainer; kpi.pwszProvName = NULL; kpi.dwProvType = PROV_RSA_FULL; kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; kpi.dwKeySpec = AT_KEYEXCHANGE; kpi.cProvParam = 0; kpi.rgProvParam = 0; if (!CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &kpi)) { THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } if (!CertAddCertificateContextToStore(m_hCertStore, pCert, CERT_STORE_ADD_REPLACE_EXISTING, NULL)){ THROW_ERR(_T("Ошибка при добавлении сертификата в личное хранилище"), GetLastError()); } | ||||
| ||||
Как я понимаю, нужно указать еще и ключ, хотя зачем, если контейнер с ним есть? но как это сделать? оч прошу, подскажите | ||||
| ||||
>> kpi.pwszContainerName = (LPWSTR)szKeyContainer; если у Вас программа не юникодная, должно быть честное преобразование ANSI-Unicode >> kpi.pwszProvName = NULL; имя провайдера тоже надо задать >> kpi.dwProvType = PROV_RSA_FULL; почему PROV_RSA_FULL? вроде речь шла о CryptoPro CSP >> kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; а вот это как раз не нужно ключ надо указывать т.к. в контейнере могут быть 2 ключа - подписи и обмена, а сертификат соответствует только одному из них. | ||||
| ||||
ywodp4mw5ns4f3 <a href = http://www.436378.com/498888.html > 26wi5k6b06rq </a> [URL=http://www.541380.com/175932.html] 7k0iz975odbnlj [/URL] os13edl85nkwihlff | ||||
| ||||
ywodp4mw5ns4f3 [URL=http://www.541380.com/175932.html] 7k0iz975odbnlj [/URL] os13edl85nkwihlff | ||||
| ||||
ywodp4mw5ns4f3 http://www.336036.com/677339.html os13edl85nkwihlff | ||||
| ||||
ywodp4mw5ns4f3 uu24ohc4kc4 os13edl85nkwihlff | ||||
| ||||
Как я раскопал в wincryptEx имя провайдера - CP_KC2_GR3410_2001_PROV_W тип провайдера - PROV_GOST_2001_DH Но каким образом указывать ключ, я найти не могу, не оставьте в беде, скажите чем и куда доваблять ключ | ||||
| ||||
Речь идет о приват ключе | ||||
| ||||
Поскольку фундаментальных знаний не имею в криптографии( точнее никаких) но по работе кровь из носу нужно сделать, То правильно ли я понял, что ключ надо импортить функцией CryptImportKey, и непостедственно в сертификат добавлять это его не нужно. Но тогда такой вопрос. Где взять непосредственно файл ключа. Ведь считывателей может быть уйма, а функция CryptGetProvParam возвращает нам только имя контейнера (папки на считывателе) и путь к этому файлу как узнать? | ||||
| ||||
Еще выяснил, что файлов ключей несколько в контейнере header.key masks.key name.key primary.key primary2.key какой из них в качестве блоба передавать функции CryptImportKey? Може подскажете литературу, где я это все прочесть смогу? | ||||
| ||||
Никакой путь к файл не надо указывать, ключ в CRYPT_KEY_PROV_INFO задается именем контейнера + типом ключа (подпись или обмен). | ||||
| ||||
Супер бест! Спасибо всем! Я в долгу :-) вот, если кому надо, функция, получающая сертифитат устанавливаем ему закрытый ключ ////////////////////////// мы начинаем кавеен void _CryptoService::SetKeyCertificate(PCCERT_CONTEXT pCert){ HCRYPTPROV m_hCryptProv = NULL; if (!CryptAcquireContext(&m_hCryptProv, NULL, NULL, 75, 0)) { m_hCryptProv = NULL; THROW_GLE(); } // Петр 30.10.2007 DWORD szKeyContainerLen = 0; LPTSTR szKeyContainer = NULL; if (!CryptGetProvParam (m_hCryptProv, PP_ENUMCONTAINERS, NULL, &szKeyContainerLen, CRYPT_FIRST)) { CryptReleaseContext(m_hCryptProv,0); THROW_ERR(_T("Ошибка при получении размера имени контейнера секретного ключа"), GetLastError()); } if (szKeyContainerLen <= 0){ CryptReleaseContext(m_hCryptProv,0); THROW_ERR(_T("Не удалось получить имя контейнера секретного ключа"), GetLastError()); } szKeyContainer = (LPTSTR)ALLOC(szKeyContainerLen); if (!CryptGetProvParam (m_hCryptProv, 110, (LPBYTE)szKeyContainer, &szKeyContainerLen, 0)) { FREE(szKeyContainer); CryptReleaseContext(m_hCryptProv,0); THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } CRYPT_KEY_PROV_INFO kpi; ZeroMemory(&kpi, sizeof(kpi)); kpi.pwszContainerName = (LPWSTR)szKeyContainer; kpi.pwszProvName = CP_KC2_GR3410_2001_PROV_W; kpi.dwProvType = PROV_GOST_2001_DH; kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; kpi.dwKeySpec = AT_KEYEXCHANGE|AT_SIGNATURE; kpi.cProvParam = 0; kpi.rgProvParam = 0; if (!CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &kpi)) { FREE(szKeyContainer); CryptReleaseContext(m_hCryptProv,0); THROW_ERR(_T("Ошибка при получении имени контейнера секретного ключа"), GetLastError()); } FREE(szKeyContainer); if (!CertAddCertificateContextToStore(m_hCertStore, pCert, CERT_STORE_ADD_REPLACE_EXISTING, NULL)){ CryptReleaseContext(m_hCryptProv,0); THROW_ERR(_T("Ошибка при добавлении сертификата в личное хранилище"), GetLastError()); } CryptReleaseContext(m_hCryptProv,0); } | ||||
| ||||
>> kpi.dwKeySpec = AT_KEYEXCHANGE|AT_SIGNATURE; Тут не должна быть сумма, нужно или AT_KEYEXCHANGE или AT_SIGNATURE - сертификат может ссылаться только на 1 ключ, т.к. в нем самом 1 ключ. | ||||
| ||||
упс, но, как ни странно, все работает?! я исходил из той логики, что этим сертификатом мы и шифруем, и подписываем, по этому написал сумму... если я выберу какой-то один тип, то смогу ли я подписывать(или шифровать) этим же сертификатом? | ||||
| ||||
Подписываете и шифруете Вы, все-таки, не сертификатом, а ключем. Ключ может быть как обмена, так и подписи. На ключе обмена можно шифровать и подписывать, на ключе подписи - только подписывать. | ||||
| ||||
Отлично, спасибо, зничит исправлю на AT_KEYEXCHANGE | ||||