| ||||
| ||||
Здесь, на форуме, много раз обсуждалось, как НЕ запрашивать повторно PIN у пользователя. У меня стоит обратная задача - для определенного набора операций запрашивать PIN каждый раз. Исходные данные: CSP 2.0 картридер Omnikey 3121 Delphi Вот (кратко) текст программы, вызываемой по кнопке "Запрос пароля". Я научился находить нужный мне провайдер с помощью функций ... hStore := CertOpenSystemStore(0, LPCSTR('MY')); ... pCertCon := CertEnumCertificatesInStore(hStore, pCertCon); if not CryptAcquireCertificatePrivateKey( pCertCon, 0, nil, hProv, flag, pfCallerFreeProv) then begin res := 'Ошибка чтения криптопровайдера: ('+InttoStr(int64(GetLastError))+') '; exit; end; ... Затем я запрашиваю пароль (PIN): CryptGetUserKey(hProv, AT_KEYEXCHANGE, key) ... Пытаюсь "забыть" пароль (прочитал, кстати, у вас на форуме, спасибо) CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, nil, 0) ... "Зачищаю" память: CryptDestroyKey(key) CryptReleaseContext(hProv, 0) CertFreeCertificateContext(pCertCon) CertCloseStore(hStore, 0) Но, при повторном нажатии весь этот текст работает БЕЗ запроса пароля у пользователя. А это очень бы хотелось :). Вот если выйти из программы и снова зайти и нажать кнопку - появится запрос пароля. Есть какие-нибудь замечания? | ||||
Ответы: | ||||
| ||||
А какой билд CSP? Рекомендуется ставить последний - 2.0.2100. | ||||
| ||||
build 2100 | ||||
| ||||
А способ хранения ключей - панель CSP - Безопасность ? | ||||
| ||||
Хранить ключи в памяти приложений | ||||
| ||||
По идее, должно работать и без очистки запомненного ПИНа. Сложность в том, что, пока контекст контейнера открыт в приложении, ПИН спрашивать повторно не будут. Контекст можт открываться явно и неявно (например, CryptAcquireCertificatePrivateKey). Можно попросить Вас посмотреть, как будет в случае, когда не используется вызов CryptAcquireCertificatePrivateKey, т.е.: CryptAcquireContext, CryptGetUserKey, CryptReleaseContext и повторно CryptAcquireContext, CryptGetUserKey, CryptReleaseContext | ||||
| ||||
А как по контексту (pCertCon) узнать криптопровайдера (hProv)? Я считал для этого как раз и используется функция CryptAcquireCertificatePrivateKey. | ||||
| ||||
Вернее я хотел сказать, что контекст нахожу по известным мне признакам (имя сертификата и серийный номер) путем перебора всех контекстов. А уж по контексту читаю криптопровайдера. А в функции CryptAcquireContext для получения криптопровайдера мне нужно указать имя контейнера. Как его вычислить? | ||||
| ||||
Вычислил (функцией CryptGetProvParam) имя нужного мне провайдера и создал ссылку на провайдера с помощью CryptAcquireContext(hProv, nil, provNane, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) но теперь при вызове CryptGetUserKey(hProv, AT_KEYEXCHANGE, key) выдает 'NTE_BAD_KEY'. (Пробовал подставить AT_SIGNATURE - та же ошибка.) Хотя когда использовал CryptAcquireCertificatePrivateKey( pCertCon, 0, nil, hProv, flag,fFreeProv) в переменной flag возвращалась 1, т.е. AT_KEYEXCHANGE. Если есть у Вас какие-нибудь мысли - подскажите. | ||||
| ||||
Флажок CRYPT_VERIFYCONTEXT лишний. Он-то как раз и говорит о том, что доступ к закрытому ключу запрещён. Определить имя контейнера, имя CSP, тип CSP по открытому контексту сертификата можно ф-ей CertGetCertificateContextProperty с параметром CERT_KEY_PROV_INFO_PROP_ID. | ||||
| ||||
Я научился вычислять имя контейнера и провайдера, но при вызове последовательности функций CryptAcquireContext, CryptGetUserKey, CryptReleaseContext не получается получить ключ - см. http://www.cryptopro.ru/cryptopro/forum/view.asp?q=3329 | ||||
| ||||
Судя по написанному в том топике - это не тот контейнер. Или открывается с неправильным именем и/или типом CSP. Вызовите описанную мной ф-ю для определения имени контейнера, имени CSP и типа CSP и используйте эти данные в CryptAcquireContext | ||||
| ||||
Попробовал: нашел контекст pCertCon затем CertGetCertificateContextProperty(pCertCon, CERT_KEY_PROV_INFO_PROP_ID, nil, siz) CertGetCertificateContextProperty(pCertCon, CERT_KEY_PROV_INFO_PROP_ID, pProvInfo, siz) CryptAcquireContext(hProv, PChar(pProvInfo.pwszContainerName), nil, pProvInfo.dwProvType, 0) -- выдает ошибку NTE_BAD_KEYSET, хотя и контейнер существует, и права доступа к нему имею... | ||||
| ||||
А какие значения имеют: 1) pProvInfo.pwszContainerName 2) PChar(pProvInfo.pwszContainerName) 3) pProvInfo.dwProvType | ||||
| ||||
ba0cc284-479e-48e3-989b-ecd341aed36f Datakey RSA CSP 1 Это похоже на правду, смотрел утилитой из поставки к OmniKey | ||||
| ||||
вдогонку. Это: pProvInfo.pwszContainerName pProvInfo.pwszProvName pProvInfo.dwProvType а PChar(pProvInfo.pwszContainerName) - это приведение типов | ||||
| ||||
"Datakey RSA CSP" - круто. Только вот... при чём здесь КриптоПро??? Собственно, весь топик - к разработчикам данного CSP. | ||||
| ||||
Наверное, Вы правы. Извините за отнятое время, но мне хотелось посоветоваться с человеком, который разбирается в использовании функций Crypto... Значит Вы считаете, что это к разработчикам провайдера? Мне казалось, что такие вещи, как появление UI как-то стандартизированы. | ||||
| ||||
Скорее наоборот, каждый разработчик делает как считает нужным, хотя и принимая во внимание, например, MSDN. | ||||
| ||||
Большое спасибо. Буду искать пути решения дальше. Еще раз спасибо! | ||||