04.10.2006 12:09:35И все-таки о повторном запросе PIN-кода Ответов: 19
Виктор
Здесь, на форуме, много раз обсуждалось, как НЕ запрашивать повторно 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)

Но, при повторном нажатии весь этот текст работает БЕЗ запроса пароля у пользователя.
А это очень бы хотелось :). Вот если выйти из программы и снова зайти
и нажать кнопку - появится запрос пароля.
Есть какие-нибудь замечания?
 
Ответы:
04.10.2006 12:50:16Василий
А какой билд CSP?
Рекомендуется ставить последний - 2.0.2100.
04.10.2006 13:01:50Виктор
build 2100
04.10.2006 13:08:06Василий
А способ хранения ключей - панель CSP - Безопасность ?
04.10.2006 13:16:46Виктор
Хранить ключи
в памяти приложений
04.10.2006 13:38:22Василий
По идее, должно работать и без очистки запомненного ПИНа. Сложность в том, что, пока контекст контейнера открыт в приложении, ПИН спрашивать повторно не будут. Контекст можт открываться явно и неявно (например, CryptAcquireCertificatePrivateKey). Можно попросить Вас посмотреть, как будет в случае, когда не используется вызов CryptAcquireCertificatePrivateKey, т.е.:
CryptAcquireContext,
CryptGetUserKey,
CryptReleaseContext
и повторно
CryptAcquireContext,
CryptGetUserKey,
CryptReleaseContext
04.10.2006 13:55:37Виктор
А как по контексту (pCertCon) узнать криптопровайдера (hProv)? Я считал для этого как раз и используется функция CryptAcquireCertificatePrivateKey.
04.10.2006 14:12:38Виктор
Вернее я хотел сказать, что контекст нахожу по известным мне признакам (имя сертификата и серийный номер) путем перебора всех контекстов. А уж по контексту читаю криптопровайдера. А в функции CryptAcquireContext для получения криптопровайдера мне нужно указать имя контейнера. Как его вычислить?
05.10.2006 12:30:29Виктор
Вычислил (функцией 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.
Если есть у Вас какие-нибудь мысли - подскажите.
06.10.2006 10:04:09Василий
Флажок CRYPT_VERIFYCONTEXT лишний. Он-то как раз и говорит о том, что доступ к закрытому ключу запрещён.
Определить имя контейнера, имя CSP, тип CSP по открытому контексту сертификата можно ф-ей CertGetCertificateContextProperty с параметром CERT_KEY_PROV_INFO_PROP_ID.
06.10.2006 10:28:04Виктор
Я научился вычислять имя контейнера и провайдера, но при вызове последовательности функций
CryptAcquireContext,
CryptGetUserKey,
CryptReleaseContext
не получается получить ключ - см. http://www.cryptopro.ru/cryptopro/forum/view.asp?q=3329
06.10.2006 11:39:20Василий
Судя по написанному в том топике - это не тот контейнер. Или открывается с неправильным именем и/или типом CSP. Вызовите описанную мной ф-ю для определения имени контейнера, имени CSP и типа CSP и используйте эти данные в CryptAcquireContext
06.10.2006 11:55:28Виктор
Попробовал:
нашел контекст 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, хотя и контейнер существует, и права доступа к нему имею...
06.10.2006 13:15:42Василий
А какие значения имеют:
1) pProvInfo.pwszContainerName
2) PChar(pProvInfo.pwszContainerName)
3) pProvInfo.dwProvType
06.10.2006 13:25:05Виктор
ba0cc284-479e-48e3-989b-ecd341aed36f
Datakey RSA CSP
1
Это похоже на правду, смотрел утилитой из поставки к OmniKey
06.10.2006 13:32:49Виктор
вдогонку. Это:
pProvInfo.pwszContainerName
pProvInfo.pwszProvName
pProvInfo.dwProvType
а PChar(pProvInfo.pwszContainerName) - это приведение типов

06.10.2006 13:36:22Василий
"Datakey RSA CSP" - круто. Только вот... при чём здесь КриптоПро??? Собственно, весь топик - к разработчикам данного CSP.
06.10.2006 13:42:36Виктор
Наверное, Вы правы. Извините за отнятое время, но мне хотелось посоветоваться с человеком, который разбирается в использовании функций Crypto...
Значит Вы считаете, что это к разработчикам провайдера? Мне казалось, что такие вещи, как появление UI как-то стандартизированы.
06.10.2006 14:04:12Василий
Скорее наоборот, каждый разработчик делает как считает нужным, хотя и принимая во внимание, например, MSDN.
06.10.2006 14:14:24Виктор
Большое спасибо.
Буду искать пути решения дальше. Еще раз спасибо!