| ||||
| ||||
Добрый день! Столкнулся со следующей проблемой - не могу получить список имен всех контейнеров для smart card. Вот код: LPCSTR ProvName = "Schlumberger Cryptographic Service Provider"; // получаем криптопровайдер if( !CryptAcquireContext(&hCryptProv, NULL, ProvName, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) ) { exit(1); } // перебираем все контейнеры в нем DWORD size; DWORD fParam = CRYPT_FIRST; while ( CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, NULL, &size, fParam) ) { BYTE* ContName = new BYTE[size]; CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, ContName, &size, fParam); printf( "Name: %s\n", (char*) ContName ); delete[] ContName; fParam = 0; } int err = GetLastError(); Результат выполнения - получаю всего одно имя контейнера (хотя я знаю что у меня их сгенерировано точно не меньше двух). Вопрос - в чем проблема и как это исправить? | ||||
Ответы: | ||||
| ||||
Читаем документацию If PP_ENUMCONTAINERS is set, the first call to the function returns the size of the maximum key-container allowed by the current provider. This is in contrast to other possible behaviors, like returning the length of the longest existing container, or the length of the current container. Subsequent enumerating calls will not change the dwLen parameter. For each enumerated container, the caller can determine the length of the null-terminated string programmatically, if desired. If one of the enumeration values is read and the pbData parameter is NULL, the CRYPT_FIRST flag must be specified for the size information to be correctly retrieved. Кстати у MS тоже ошибка в перечислителе в wlnotify.dll - получают каждый второй контейнер (как и у Вас). И они не торопятся ее исправлять. | ||||
| ||||
maxdm Документацию-то я читал - однако не понял причем тут моя проблема. Первый получаю с флагом CRYPT_FIRST, дальнейшие просто вытаскиваем... Что-то тут не то. Решение проблемы должно быть. | ||||
| ||||
Читаем документацию внимательнее. Запущено два цикла перечислителя while ( CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, NULL, &size, fParam) ) - первый { BYTE* ContName = new BYTE[size]; CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, ContName, &size, fParam); - второй printf( "Name: %s\n", (char*) ContName ); delete[] ContName; fParam = 0; } должно быть так fParam = CRYPT_FIRST; CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, NULL, &size, fParam); BYTE* ContName = new BYTE[size]; while ( CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, ContName, &size, fParam) ) { printf( "Name: %s\n", (char*) ContName ); fParam = 0; } | ||||
| ||||
maxdm Вы не правы :) В первом случае - получаем размер, который необходимо выделить под строку для названия криптопровайдера, поотм выделяем память, во втором вызове считываем имя, выводим на экран и удаляем... | ||||
| ||||
Итак, после недолгих проб получил потрясающий результат. Поехали.... Используя пример из MSDN получаю список всех криптопровайдеров. Далее, для каждого из полученных криптопровайдеров, перечисляю их контейнеры. Код привожу ниже (без проверки на ошибки и т.п. - чтобы места меньше занимало): while( CryptEnumProviders(dwIndex, NULL, 0, &dwType, NULL, &cbName) ) { CryptEnumProviders(dwIndex++, NULL, 0, &dwType, (LPSTR)provName, &cbName); printf ("Provider Name: %s\n Name list for available container:\n", (char*)provName ); // получаем криптопровайдер if( !CryptAcquireContext(&hCryptProv, NULL, (char*) provName, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) ) continue; // перебираем все контейнеры в нем DWORD size = 1000; BYTE ContName[1000]; DWORD fParam = CRYPT_FIRST; DWORD cnt = 0; while ( CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, ContName, &size, fParam) ) { fParam = 0; printf( " container name: %s\n", (char*) ContName ); cnt++; } printf("Total containers: %d.\n", cnt); CryptReleaseContext(hCryptProv,0); printf("\n\n\n"); } // End while loop. Получилось, что для еТокена я вижу 4 контейнера, для всех микрософтовских контейнеров - 53 штуки и для смарт карты - 1. Меняем алгоритм перечисления контейнеров: while ( CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, NULL, &size, fParam) ) { // можно динамически выделить память под имя контейнера равную size CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, ContName, &size, fParam); fParam = 0; ... Получаю такой результат: еТокен - 7 контейнеров Микрософтовых - 27 контейнеров смарт-карта - 1 контейнер... Мне точно известно, что контейнеров на еТокене 7 (смотрим через утилиту еТокена). Микрософтовых мне думается все-таки реально 53 стоит. А вот как понять сколько реально на смарт карте - я не знаю. Их там точно минимум два (могу выполнять операции проставления ЭЦП двумя разными ключами с нее). Похоже, что счетчики количества перечисляемых контейнеров в каждом криптопровайдере работают по-своему. Я не смог найти в Интернете нормальной базы знаний по таким вопросам. Буду рад любой помощи. Задача все та же - правильно получить список всех контейнеров с микрософтового, еТокеновского и смарт-карточного (Шлембурже) криптопровайдеров. | ||||
| ||||
Я на это уже натыкался - и писал в MS - безрезультатно. Наш провайдер реализует первый вариант, чтобы быть похожим на MS. | ||||
| ||||
А почему в CryptAcquireContext(&hCryptProv, NULL, (char*) provName, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) используется константа PROV_RSA_FULL, а не dwType, полученный на предыдущем шаге? Что будет, если поменять? | ||||
| ||||
Добрый день! Поменял - теперь корректно стало отрабатываться для типов криптопровайдеров не PROV_RSA_FULL. Раньше при выполнении функции CryptAcquireContext выдавалась ошибка. Но по сути - это никак не повлияло на стоящую передо мной проблему. Как работало криво с разными криптопровайдерами, так и работает. Количество контейнеров, демонстрируемое при работе приложения, все также различается в зависимости от метода получения контейнеров при перечислении (с двумя вызовами или с одним). Какие еще есть предложения по решению данного вопроса? | ||||
| ||||
По поводу eToken CSP - обратитесь с вопросом к производителю этого оборудования и ПО. Это компания "Аладдин", http://www.aladdin.ru Интересно услышать их мнение. | ||||