| ||||
| ||||
возможно ли без знания пин-кода? CryptExportKey(... PUBLICKEYBLOB ...) и CryptExportPublicKeyInfo его требуют. | ||||
Ответы: | ||||
| ||||
Если Вы используете "КриптоПро CSP" версии 3.0 или выше, то ПИН для доступа к открытому ключу не нужен. | ||||
| ||||
Спасибо. По информации из панели управления - CSP KC1 3.0.3300.2. Пин-код при вызовах этих функций на свежесозданные контейнеры запрашивается. Может, где-то что-то застряло от предыдущих установок CSP 2.0. Как посмотреть, где и что не так? | ||||
| ||||
Ваша правда, неправильно я написал. Без ПИН-кода можно добыть сертификат, если он есть в ключевом контейнере (CryptGetKeyParam, KP_CERTIFICATE). А уже потом из него взять открытый ключ. Вот пример: HCRYPTPROV hCertContainer = 0; HCRYPTKEY hKey, hPubKey = 0; LPBYTE pbUserCert; DWORD dwCertLen; PCCERT_CONTEXT pUserCert=0; DWORD dwUserCertLength=0; if(!CryptAcquireContext(&hCertContainer, "Cont1", NULL, 75, 0 )) HandleError("CryptAcquireContext"); if(!CryptGetUserKey( hCertContainer, AT_KEYEXCHANGE, &hKey)) HandleError("CryptGetUserKey"); /* Получить сертификат.*/ if (!CryptGetKeyParam (hKey, KP_CERTIFICATE, NULL, &dwUserCertLength, 0)) { HandleError ("Error during GetKeyParam.\n"); } pbUserCert = malloc (dwUserCertLength); if (pbUserCert == NULL) { HandleError ("Error during malloc.\n"); } if (!CryptGetKeyParam (hKey, KP_CERTIFICATE, pbUserCert, &dwUserCertLength, 0)) { HandleError ("Error during GetKeyParam.\n"); } /* Декодировать сертификат */ pUserCert = CertCreateCertificateContext ( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pbUserCert, dwUserCertLength); if (pUserCert == NULL) { HandleError ("Error during CertCreateCertificateContext.\n"); } /* получаем хендл открытого ключа */ if (!CryptImportPublicKeyInfoEx ( hCertContainer, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(pUserCert->pCertInfo->SubjectPublicKeyInfo), 0, 0, NULL, &hPubKey)) HandleError ("Error during CryptImportPublicKeyInfoEx.\n"); ... CryptReleaseContext(hCertContainer,0); | ||||
| ||||
К сожалению, это несколько не то: стоит обратная задача - по сертификату найти соотвествующий ему контейнер (а физически сертификат в контейнер не помещается). Да и сертификат, как показывает практика, в контейнер может быть установлен любой. | ||||
| ||||
> Да и сертификат, как показывает практика, в контейнер может быть установлен любой. Штатными средствами это невозможно, только прямым вызовом CryptSetKeyParam с параметром KP_CERTIFICATE. По существу Вашей задачи - непонятно, сертификат берётся из хранилища или нет. Если первое - то там есть ссылка на контейнер, т.е. имя контейнера получить можно. Если второе - вряд ли вообще существует решение, т.к. даже при переборе всех контейнеров можно не найти нужный, поскольку он может быть на неподключенном съёмном носителе. | ||||
| ||||
Эта задача частично решена в продукте КриптоПро Winlogon и полностью решена в КриптоПро CSP, открытый ключ в этом случае берется из сертификата в контейнере (если последний существует). Соответствие закрытому ключу контролируется по контрольной сумме. Открытого ключа в чистом виде как не было в контейнере, так и нет, поскольку его хранение избыточно. | ||||
| ||||
>По существу Вашей задачи - непонятно, сертификат берётся из хранилища или нет. Хранилище есть, но свое (общая для всех пользователей БД). Имя контейнера значения не имеет, поскольку это вполне может быть и копия оригинального контейнера с другим именем. Посему вопрос остается открытым. | ||||
| ||||
Можно узнать поподробнее про функционирование системы? Возможно, есть какие-то обходные пути. Если хранилище общее для всех пользователей - то ключи у пользователей на съемных носителях? | ||||
| ||||
Поддерживаю вопрос Кирилла. Давайте уточним саму постановку задачи. Вот есть сертификат. Можно делать все операции, не требующие закрытого ключа (например, проверять ЭЦП документа). Вы формулируете такую задачу - узнать, какой ключевой контейнер соответствует этому сертификату, причём, без ввода пароля (ПИН-кода). Собственно, вопрос - а зачем? Если для того, чтобы в дальнейшем использовать секретный ключ из этого контейнера - то по-любому нужно будет вводить пароль или ПИН. Допустим, Вы рассматриваете ситуацию, когда нельзя запоминать имя контейнера по причине того, что может быть сделана копия контейнера. Тогда к контейнеру по имени обращаться нельзя и вопрос в диалоге для пользователя будет звучать так: "Вставьте какой-нибудь носитель с каким-нибудь контейнером ключа, вдруг ключ в нём соответствует данному сертификату" - всё это очень странно. | ||||
| ||||
Вводить пин-код, действительно, надо будет. Но тогда, когда нужно и только к нужному контейнеру. Требование заказчика, увы. Пользователь заходит в систему по обычному логину-паролю. Когда требуется операция, требующая персонального ключа - запускается поиск "подходящего" контейнера (сертификаты в БД имеют привязку к пользователю). Если не нашли, то отклонили текущую операцию, если нашли - спросили пин на конкретный контейнер и воспользвались им. Кажется, такая схема вполне имеет право на существования. Ключевое, повторюсь: имя контейнера неизвестно, сертификата в контейнере нет, каждый контейнер на носителе может иметь свой собственный пин(пароль). Ну и минимум запросов к пользователю. | ||||
| ||||
Вы хотите быть хитрее чем MS :) У них большая часть криптографии построена на том, что сертификат, установленный в системе, имеет ссылку на секретный ключ либо не имеет этого ключа вообще. А Вы хотите это выкинуть, не потеряв при этом в функциональности. Устанавливайте сертификат в контейнер и Ваша схема будет как-то работать. Кстати о таком моменте Вы подумали - по сертификату нельзя узнать ни имя провайдера, ни тип, ни тип ключа - как Вы это будете получать? При каждом обращении перебирать все установленные в системе провайдеры? | ||||
| ||||
Нет, я всего лишь хочу как-то получить открытый ключ, который, несмотря на то, что он открытый, все равно требует пин-кода :) И какой функциональности идет речь? О невозможности без установленного в системе сертификата подписать или проверить подпись? Так это все реализовано и работает. Большего и не надо. Так что выкидывать, по сути, нечего. А по поводу установки сертификата - ранее я написал, что сертификат физически не помещается. Размер больше 2К, носитель - DS 1995. | ||||
| ||||
Только Вы его хотите получить оттуда, где у Вас места нет для его хранения. При этом хранить базу сертификатов как делает MS, с ссылками на контейнер, Вы тоже не хотите. Очень сильные ограничения на решение получаются. | ||||
| ||||
>Только Вы его хотите получить оттуда, где у Вас места нет для его хранения. Простите, контейнер-то там помещается, и даже два, так что места именно под то, что я хочу получить, там все-таки есть :) >При этом хранить базу сертификатов как делает MS, с ссылками на контейнер, Вы тоже не хотите. Скорее, не можем, система уже работает. К вопросу об ограничениях - невозможность без лишних телодвижений использовать на одном компьютере контейнеры с одинаковыми именами но с разных носителей (и копия с тем же именем на другой носитель) - это тоже оно :) А гарантий уникальности имени нет никаких. | ||||
| ||||
Вы недавно писали, что места физически нет - а теперь оно есть? Без сертификата ОК в контейнере смысла не имеет, это действительно избыточная информация. | ||||
| ||||
Давайте не будем играть словами: я писал, что места нет под сертификат, а не под контейнер. Наверное, это все-таки разные вещи. >Без сертификата ОК в контейнере смысла не имеет, это действительно избыточная информация. Запрос сертификата ОК без "сертификата смысла не имеет"? И предназначенные, в частности, для этого, функции КриптоАпи из первого поста, реализованные в вашем продукте и работающие без сертификата, тоже? Наверное, все-таки, не более избыточная, чем сам сертификат. И базовые операции, вроде проверки подписи или шифрования сертификата все-таки не требуют :) Спасибо за консультацию. | ||||
| ||||
Я предлагаю такой вариант. Раз Вы не хотите использовать имена контейнеров хотя все остальные используют, и не жалуются :-) и не хотите, чтобы спрашивались пароли на контейнеры - то и не ставьте пароли на контейнеры. Тогда достаточно будет самого факта предъявления таблетки в нужный момент. | ||||
| ||||
Спасибо, такой вариант рассматривался. Однаку у пользователя есть возможность создания контейнера самостоятельно (непосредственно из программы). Каким образом можно программно создать контейнер с заданным (или пустым) паролем? Не показывая запрос пароля пользователю? | ||||
| ||||
Программно - легко. Достаточно установить пароль в явном виде, тогда он не будет спрашиваться у пользователя. Ф-я CryptSetProvParam, параметр PP_KEYEXCHANGE_PIN: HCRYPTPROV hProv=0; HCRYPTKEY hKey=0; char* pass = ""; CryptAcquireContext( &hProv, "Cont1", NULL, 75, CRYPT_NEWKEYSET ); CryptSetProvParam(hProv, PP_KEYEXCHANGE_PIN, (BYTE*)pass, 0); CryptGenKey( hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey); //тут пароль уже не спросят | ||||
| ||||
Пожалуйста. >> Давайте не будем играть словами: я писал, что места нет под >> сертификат, а не под контейнер. Наверное, это все- >> таки ,разные вещи. Я не очень хорошо знаком с устройством DS 1995, там место под сертификаты и под контейнеры физически разное? Если же нет и оно общее - то туда куда влезет 2 контейнера точно влезет контейнер и сертификат (сертификат на 2001 ГОСТЕ в DER занимает 300 байт или меньше). >> Запрос сертификата ОК без "сертификата смысла не имеет"? Вопрос не понял. Что значит запрос сертификата без сертификата? А все функции CryptoAPI, в т.ч. и реализованные в нашем продукте, спроектированы и функционируют так, что для операций, выполняющихся только с участием ОК контейнер не требуется - провайдер инициализируется со специальным флагом CRYPT_VERIFYCONTEXT. Информация избыточная вот почему - имея контейнер с ключем, Вы никак не получите сертификат, который этому контейнеру соответствует, но легко можете вычислить ОК. Поэтому ОК в контейнере и не хранят - собственно, пользоватеь свой ОК редко использует, разве что ведет секретный архив. | ||||