Статус: Участник
Группы: Участники
Зарегистрирован: 19.09.2019(UTC) Сообщений: 15  Откуда: Москва Сказал(а) «Спасибо»: 4 раз
|
Коллеги, доброго времени суток. Реализовали установку ПИН через последовательность вызовов: 1 Код:CertOpenSystemStore(0, strStore)
2 Код:pCert = CertFindCertificateInStore
3 Код:CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
После этого контекст сертификата должен становиться не персистентным и любые изменения к нему не должны сохраняться? 4 Код:CertGetCertificateContextProperty(pCert,
CERT_KEY_PROV_INFO_PROP_ID,
pCryptKeyProvInfo,
&szData))
5 Код:DWORD keyType = pCryptKeyProvInfo->dwKeySpec==AT_SIGNATURE ? PP_SIGNATURE_PIN: PP_KEYEXCHANGE_PIN;
CRYPT_KEY_PROV_PARAM key_prov_param;
memset(&key_prov_param, 0, sizeof(CRYPT_KEY_PROV_PARAM));
key_prov_param.dwFlags = 0;
key_prov_param.dwParam = keyType;
key_prov_param.cbData = static_cast<DWORD>(pin.size()+1);
key_prov_param.pbData = (BYTE *)pin.c_str();
pCryptKeyProvInfo->cProvParam = 1;
pCryptKeyProvInfo->rgProvParam = &key_prov_param;
6 Код:CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, pCryptKeyProvInfo))
7 Насколько я понимаю опциональный шаг Код:BOOL isHProvNeedToFree = false;
HCRYPTPROV hProv = NULL;
BOOST_SCOPE_EXIT(&hProv, &isHProvNeedToFree)
{
if (hProv && isHProvNeedToFree)
{
::CryptReleaseContext(hProv, 0);
}
}
BOOST_SCOPE_EXIT_END;
CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_SILENT_FLAG,
NULL,
&hProv,
&pCryptKeyProvInfo->dwKeySpec,
&isHProvNeedToFree))
После этого пароль успешно устанавливается и операция подписи происходит успешно без окна запроса ПИН. При этом кэш ПИН в панели управления CryptoPro не досупен для отчистки. 8 Код:CRYPT_SIGN_MESSAGE_PARA SigParams;
SigParams.pSigningCert = pCert;
SigParams.dwFlags = CRYPT_MESSAGE_SILENT_KEYSET_FLAG;
...
CryptSignMessage(&SigParams,...)
...
::CertFreeCertificateContext(pCert);
Однако, ПИН похоже каким-то образом кэшируется и не совсем понятно как? После перезагрузки PC или приложения (даже без флага CRYPT_ACQUIRE_CACHE_FLAG в CryptAcquireCertificatePrivateKey), при повторном вызове (1-3)(8) ПИН не запрашивается. В документации на CryptSignMessage сказано, что он дергает CryptAcquireContext используя CRYPT_KEY_PROV_INFO из pCert сертификата, и должен кэшировать хэндл провайдера только при передаче в функцию флагов CERT_SET_KEY_CONTEXT_PROP_ID, CERT_SET_KEY_PROV_HANDLE_PROP_ID. При выставлении флага CRYPT_ACQUIRE_CACHE_FLAG в CryptAcquireCertificatePrivateKey в вызове перед CryptSignMessage хэндл должен кэшироваться только до момента освобождения CertFreeCertificateContext, однако этого тоже не проиходит. Следующий вызов CryptSignMessage после CertFreeCertificateContext и затем (1-3) также не требует ПИН. По результатам экспериментов кэш ПИН можно сбросить вызовом (1-7) с неправильным pin. Закрытая часть хранится в реестре, если это важно. Подскажите, где этот кэш ПИН в итоге хранится? Его нельзя сбросить через панель КриптоПро, он по идее не должен сохраниться после CertSetCertificateContextProperty т.к. контекст не персистентен после CertCloseStore (3) ? Остается, что только CryptSignMessage может его куда-то сохранить? Куда? Что можно сделать, чтобы заставить CryptSignMessage не использовать закэшированный ПИН на вызовах после первого? Этот процесс работы с кэш ПИН можно регулировать через панель управления КриптоПро или например через комбинацию каких-то других флагов в процессе (1-8)? Отредактировано пользователем 30 марта 2021 г. 11:32:46(UTC)
| Причина: Не указана
|
|
|
|
Статус: Эксперт
Группы: Участники
Зарегистрирован: 05.03.2015(UTC) Сообщений: 1,602  Откуда: Иркутская область Сказал(а) «Спасибо»: 110 раз Поблагодарили: 395 раз в 366 постах
|
Автор: trunovsergey  по идее не должен сохраниться после CertSetCertificateContextProperty т.к. контекст не персистентен после CertCloseStore (3)? Добрый день. Если кратко, то флаг в CertCloseStore для такого сценария нужен нулевой.
Насколько я понимаю примечания Майкрософт к функциям, то на шаге 3 (CertCloseStore): 1) либо хранилище принудительно закрывается и контекст сертификата становится недействительным, следовательно обращение к контексту сертификата дает исключение и с хорошей вероятностью это означает крах приложения; 2) либо хранилище остается открытым пока не закроете контекст сертификата (то есть операции закрытия хранилища реально не происходит, как будто шага 3 нет) - тогда это все тот же контекст сертификата, который связан с хранилищем. Указанный Вами флаг CERT_CLOSE_STORE_CHECK_FLAG как раз дает отложенное закрытие. 3) либо хранилище закрывается, контексты сертификатов остаются, изменения могут не сохраниться в хранилище (флаг = 0).
Проверить, сохранились ли изменения в самом хранилище можете выполнив 1-7 и освободив все, потом 1-4, сразу после 4 посмотрев pCryptKeyProvInfo->cProvParam pCryptKeyProvInfo->rgProvParam . Если данные о пин-коде сохранились, то вопрос "где закэшировано" отпадает.
По моим представлениям, чтобы изменения не сохранились, либо нужно при вызове CertCloseStore указать флаг 0 либо где-то между шагом 4 и шагом 6 нужно "пересоздать" контекст сертификата pCert без привязки к хранилищу: получить данные сертификата (это поля pbCertEncoded/cbCertEncoded в памяти, на которую указывает контекст pCert); данные ссылки на контейнер по идее получены в шаге 4; закрыть контекст CertFreeCertificateContext (что вызовет реальное выполнение отложенного на шаге 3 закрытия хранилища CertCloseStore). Далее создать новый контекст из данных сертификата CertCreateCertificateContext; проставить ссылку на контейнер (что по идее сделает шаг 6). После такого pCert точно не будет связан с хранилищем (пока явно не добавите в хранилище), но будет содержать ссылку на закрытый ключ и пин-код.
Отредактировано пользователем 1 апреля 2021 г. 11:44:35(UTC)
| Причина: Не указана
|
 1 пользователь поблагодарил two_oceans за этот пост.
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 19.09.2019(UTC) Сообщений: 15  Откуда: Москва Сказал(а) «Спасибо»: 4 раз
|
Спасибо, похоже придется делать копию контекста сертификата. CertCloseStore с флагом 0 имеет такой же эффект как и с CERT_CLOSE_STORE_CHECK_FLAG. И это странно т.к. в документации для флага 0: Цитата:By default, memory used to store contexts with reference count greater than zero is not freed when a certificate store is closed. References to those contexts remain valid; however, this can cause memory leaks. Also, any changes made to the properties of a context after the store has been closed are not persisted.
Для CERT_CLOSE_STORE_CHECK_FLAG также кажется, что подразумевается то же самое: Цитата:When this flag is set, and all certificate, CRL, or CTL contexts have not been released, the function returns FALSE and GetLastError returns CRYPT_E_PENDING_CLOSE. Note that the store is still closed when FALSE is returned and the memory for any active contexts is not freed т.е. store должен все равно закрыться, но возможно это произойдет не сразу? С учетом того, что в контексте сертификата также хранится указатель на store, видимо полное закрытие возможно, когда все контексты будут закрыты? Иначе выходит нарушается Цитата:Also, any changes made to the properties of a context after the store has been closed are not persisted.
|
|
|
|
Статус: Эксперт
Группы: Участники
Зарегистрирован: 05.03.2015(UTC) Сообщений: 1,602  Откуда: Иркутская область Сказал(а) «Спасибо»: 110 раз Поблагодарили: 395 раз в 366 постах
|
Автор: trunovsergey  Спасибо, похоже придется делать копию контекста сертификата. Слово "пересоздание" подходит наверно больше для алгоритма "закрыть-создать", так как еще можно "копировать" вызовом CertDuplicateContext. Вот только реально копирования в CertDuplicateContext не происходит, просто увеличивается счетчик ссылок на контекст сертификата и возвращается тот же указатель, никаких изменений связи с хранилищем не происходит. Автор: trunovsergey  Для CERT_CLOSE_STORE_CHECK_FLAG... store должен все равно закрыться, но возможно это произойдет не сразу? ... видимо полное закрытие возможно, когда все контексты будут закрыты? Похоже что так. Я понимаю так (пусть меня поправят если ошибаюсь): хэндл самого хранилища HSTORE закроется для текущего процесса (CRYPT_E_PENDING_CLOSE... Note that the store is still closed when FALSE is returned), но и сам контекст "жив" и связь контекста сертификата с хранилищем сохраняется (то есть "где-то за кадром" хранилище все еще не выгружено из памяти, хотя и недоступно напрямую).
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 19.09.2019(UTC) Сообщений: 15  Откуда: Москва Сказал(а) «Спасибо»: 4 раз
|
Коллеги, похоже тут есть нюансы такого подхода с рутокенами. При пересоздании контекста pCert без привязки к хранилищу: Цитата:получить данные сертификата (это поля pbCertEncoded/cbCertEncoded в памяти, на которую указывает контекст pCert); данные ссылки на контейнер по идее получены в шаге 4; закрыть контекст CertFreeCertificateContext (что вызовет реальное выполнение отложенного на шаге 3 закрытия хранилища CertCloseStore). Далее создать новый контекст из данных сертификата CertCreateCertificateContext; проставить ссылку на контейнер (что по идее сделает шаг 6). Пин все также кэшируется и при тестировании закрытой части по сертификату запрос на ввод ПИН отсутствует, при этом при работе с закрытыми частями в реестре все работает. Пересоздаем контекст сертификата так: Код:CertGetCertificateContextProperty(pCert,
CERT_KEY_PROV_INFO_PROP_ID,
pCryptKeyProvInfo,
&szData)
newPcert = CertCreateCertificateContext(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ,
pCert->pbCertEncoded, pCert->cbCertEncoded);
CertFreeCertificateContext(pCert);
Далее устанавливаем ПИН в новый контекст сертификата: Код:DWORD keyType = pCryptKeyProvInfo->dwKeySpec==AT_SIGNATURE ? PP_SIGNATURE_PIN: PP_KEYEXCHANGE_PIN;
CRYPT_KEY_PROV_PARAM key_prov_param;
memset(&key_prov_param, 0, sizeof(CRYPT_KEY_PROV_PARAM));
key_prov_param.dwFlags = 0;
key_prov_param.dwParam = keyType;
key_prov_param.cbData = static_cast<DWORD>(pin.size()+1);
key_prov_param.pbData = (BYTE *)pin.c_str();
pCryptKeyProvInfo->cProvParam = 1;
pCryptKeyProvInfo->rgProvParam = &key_prov_param;
CertSetCertificateContextProperty(newPcert, CERT_KEY_PROV_INFO_PROP_ID,
0, pCryptKeyProvInfo);
Пересозданный контекст сертификата newPcert явно не добавляется в хранилище и после использования только освобождается. Пробовал вызывать CertSetCertificateContextProperty с CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, что по идее явно говорит провайдеру не кэшировать изменения контекста. "If CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG is set, any context property set is not persisted.", однако, эффект такой же - ПИН кэшируется. Проверил как происходит тот же процесс, только через панель управления КриптоПро 5.0.11635 КС1: 1. Сбросил ПИН через утилиту рутокена. 2. В панели КриптоПро при тестировании контейнера указал ПИН и согласился сохранить в системе. 3. Сбросил ПИН в панели КриптоПро Сервис->Удалить сохраненные пароли 4. Последующее тестирование контейнера не требует ПИН Не совсем понятно, почему при той же последовательности действий работа с ПИН закрытой части на рутокене отличается от работы с закрытой закрытой частью в реестре и через панель КриптоПро и через наш код? Является ли поведение со сбросом ПИН через панель КриптоПро при работе с рутокеном ошибкой? Отредактировано пользователем 17 мая 2021 г. 19:15:03(UTC)
| Причина: Не указана
|
|
|
|
Статус: Эксперт
Группы: Участники
Зарегистрирован: 05.03.2015(UTC) Сообщений: 1,602  Откуда: Иркутская область Сказал(а) «Спасибо»: 110 раз Поблагодарили: 395 раз в 366 постах
|
Добрый день. Код вроде бы верный, разве что я бы все же (на всякий случай) выгрузил данные сертификата в отдельную переменную, а не "прикуривал один от другого". Хотя... так наверно удобнее сравнивать не указывают ли они на один адрес. С контейнером в реестре теперь спрашивает пин-код? Странное поведение, выскажу свои предположения. Цитата:Коллеги, похоже тут есть нюансы такого подхода с рутокенами. Вспоминается, что с какой-то версии КриптоПро пробует ввести стандартные пароли (12345678 1234567890 9876543210 и т.д.) на токен автоматически. На токене пин-код ставится как правило на весь токен, а не конкретно на контейнер. Сначала пробуется стандартный, если он подошел, то у пользователя не спрашивает пин-код. Поэтому токены со стандартным пин-кодом не являются показателем кэшируется ли пин-код. Интересно как именно было реализовано "Сбросил ПИН через утилиту рутокена" (поменяли на нестандартный?) С какой целью вообще сохраняли пароль при тестировании? Или с реестром сохранение-удаление пин-кода не вызывает проблемы? Есть ли зависимость от времени между удалением сохраненного пин-кода и проверкой запросит ли пин-код? Что указано на вкладке Безопасность? Использовать службу хранения ключей? Включить кэширование?
Вообще один раз сохранили - потом от него достаточно трудно "избавится". Операция удаления пин-кода по практике работает не мгновенно: хотя пин-код сразу удаляется из раздела реестра КриптоПро, но похоже остается в каком-то объекте (или службе) в памяти и иногда нужно повторить удаление пин-кода пару раз с перезагрузкой компьютера после каждой попытки чтобы пин-код начало снова запрашивать после удаления. Кто-то говорил, что обходился перезагрузкой службы криптопровайдера, но у меня как-то не сложилось. С другой стороны, точной информации у меня все-таки нет, возможно это и не служба криптопровайдера, а некий таймаут или просто открытие нового экземпляра хранилища (был случай, что оснастка сертификаты показывала неверную информацию о цепочках до повторного открытия оснастки).
Еще предположение, что какое-то время сохраняется сессия связи с токеном, а без установки новой сессии не запрашивается пин-код повторно? Суть в том, что канал связи с токеном (в отличие от флешки/реестра) защищается специальным алгоритмом от вмешательства извне в передаваемые токену и от токена данные (конечно если есть техническая возможность для модели токенов). Если токен вытащить, некоторое время подождать (перебрать разный интервал от 5 секунд до получаса, например) и снова подключить - все равно не спросит пин-код?
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 19.09.2019(UTC) Сообщений: 15  Откуда: Москва Сказал(а) «Спасибо»: 4 раз
|
Цитата:С контейнером в реестре теперь спрашивает пин-код? Да, в случае с реестром пароль запрашивается каждый раз, к чему и стремимся со всеми видами контейнеров. Цитата:Вспоминается, что с какой-то версии КриптоПро пробует ввести стандартные пароли (12345678 1234567890 9876543210 и т.д.) на токен автоматически. Очень интересное поведение... В рутокенах есть юзер пароль (не стандартный), а есть администратора (стандартный). При тестировании контейнера через панель КриптоПро первый раз пароль все-таки запрашивается. Значит все-таки попытка подстановки стандартного пароля, если таковая производится не прошла. Цитата:Интересно как именно было реализовано "Сбросил ПИН через утилиту рутокена" (поменяли на нестандартный?) Да, меняем, например, на 111111 с 1111 юзер пароль. Цитата:С какой целью вообще сохраняли пароль при тестировании? Пытались проверить как сам КриптоПро делает операцию сохранения ПИН для рутокена и сравнить с поведением реализуемым нашим кодом. Поведение показалось идентичным. ПИН первый раз устанавливается и далее не запрашивается, даже если его удалить через панель КриптоПро. Цитата:Или с реестром сохранение-удаление пин-кода не вызывает проблемы? С реестром все работает ожидаемо. ПИН сбрасывается. Цитата:Что указано на вкладке Безопасность? Использовать службу хранения ключей? Включить кэширование? Нет, мы службу хранения и кэширование явно не используем. Стоят галки "Хранить ключи в приложении" и "Усиленый контроль использования ключей". Приложение для тестирования, перезапускалось после установки ПИН и не должно было бы сохранить ПИН в кэш. Во всяком случае, этот же код для контейнеров в реестре не сохраняет ПИН нигде. Основная проблема в том, что один и тот же код для реестра и для рутокенов работает по-разному. А хотелось бы, чтобы работало одинаково (ПИН не сохранять нигде). Решение перевтыкать токен конечно потенциально тоже решение (можно пробовать даже делать это программно и как-то автоматизировать), но если есть какое-то решение только в рамках CAPI (на первый взгляд можно только явно сбрасывать ПИН в handle провайдера для рутокенов?) Код:SetProvParam(hProv, PP_DELETE_SAVED_PASSWD, 0, 0);
Но опять же, если панель КриптоПро делает так же и ждать сброса некое время - не очень чистое решение, мягко говоря. Отредактировано пользователем 19 мая 2021 г. 15:47:54(UTC)
| Причина: Не указана
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 19.09.2019(UTC) Сообщений: 15  Откуда: Москва Сказал(а) «Спасибо»: 4 раз
|
UPD: при тестировании контейнера с Рутокена через панель КриптоПро, после первого ввода ПИН, даже без галки "Сохранить пароль в системе" пароль все-равно сохраняется. Дальнейшие тестирование этого контейнера пароль больше не требует! Удалить пароль через панель КриптоПро нельзя, спустя 2ч. пароль также не требуется. Как это вообще может быть? Отредактировано пользователем 19 мая 2021 г. 15:41:31(UTC)
| Причина: Не указана
|
|
|
|
Статус: Эксперт
Группы: Участники
Зарегистрирован: 05.03.2015(UTC) Сообщений: 1,602  Откуда: Иркутская область Сказал(а) «Спасибо»: 110 раз Поблагодарили: 395 раз в 366 постах
|
Цитата:Основная проблема в том, что один и тот же код для реестра и для рутокенов работает по-разному. Интересно, значит и правда дело в токене. Цитата:Решение перевтыкать токен конечно потенциально тоже решение (можно пробовать даже делать это программно и как-то автоматизировать), но если есть какое-то решение только в рамках CAPI ... Выше я предложил "для отладки" проверить сработает ли как требуется если "перевтыкать" токен. Если "внезапно" работает, то высока вероятность что дело не в самом API, а именно во взаимодействии между криптопровайдером и токеном. По такой узкой теме лучше спрашивать достоверные пояснения или у отдела по работе с ФКН КриптоПро (на форуме Агафьин Сергей) или у производителей рутокена. Еще наверно поможет указать версию КриптоПро, операционную систему (windows или *nix), модель рутокена, версию и дату драйверов рутокена. Работа с токенами менялась в последних версиях криптопровайдера, в частности, было упоминание на форуме, что в новейшей версии теперь полноценная работа через PKCS#11 (с Рутокеном ЭЦП 2.0). Вообще я не вижу как на windows само извлечение токена можно сделать программно - при вызове функции безопасного излечения USB устройство переходит в состояние "ожидает извлечения" пока его физически не отсоединят-присоединят, поиск нового оборудования его игнорирует. Где-то говорилось, что можно убрать устройство (не отключая физически) из списка смарт-карт (из-за ограничения windows на количество перечисляемых смарт-карт при большом количестве токенов видны не все), потом вернуть, но не знаю применимо ли для разрыва связи.
|
 1 пользователь поблагодарил two_oceans за этот пост.
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close