Не удаляется контейнер 'Aktiv ruToken CSP v1.0' на Rutoken Lite

Доброго времени суток.
После форматирования Rutoken Lite с помощью rtPKCS11ECP.dll невозможно удалить контейнер с помощью криптопровайдера 'Aktiv ruToken CSP v1.0'. Проблемы нет, если форматирование производить с помощью библиотеки rtPKCS11.dll.
При вызове 'CryptAcquireContext(&prov2, full_container_name.c_str(), g_prov_name, g_prov_type, CRYPT_SILENT | CRYPT_DELETEKEYSET)' возникает ошибка 0x8007001f.

Проблема воспроизводится на драйверах:
v.2.100.00.0542_20.11.2014
v.4.0.0.0_31.08.2015
v.4.0.1.0_14.10.2015
v.4.0.2.0_23.10.2015
v.4.0.5.0_30.12.2015

На более ранних версиях ошибка не воспроизводится.

Проверено на операционных системах: windows 7 x64, windows 8.1 x64 и  windows 8.1 x86

В примере файл Common.h взят из SDK

Пример:

#include <Windows.h>
#include <WinCrypt.h>
#include <iostream>
#include <string>

#include "Common.h"

#define MAX_ADMIN_RETRY_COUNT 10
#define MAX_USER_RETRY_COUNT 10

DWORD g_prov_type = 0x1;
LPCSTR g_prov_name = "Aktiv ruToken CSP v1.0";
LPCSTR g_token_pass = "12345678";

bool InitTokenEx();
bool InitToken();
bool DeleteContainer(LPCSTR container_name, LPCSTR reader_name);
bool GenerateKeyPair(LPCSTR container_name, LPCSTR reader_name);

int main()
{
    LPCSTR container_name = "Test container!";
    LPCSTR reader_name = "\\\\.\\Aktiv Rutoken lite 0\\";
    //LPCSTR reader_name = "\\\\.\\Aktiv Rutoken ECP 0\\";
    //LPCSTR reader_name = "\\\\.\\Aktiv Co. ruToken 0\\";

    if (!InitTokenEx())
    {
        return 0;
    }

    if (!GenerateKeyPair(container_name, reader_name))
    {
        return 0;
    }

    if (!DeleteContainer(container_name, reader_name))
    {
        return 0;
    }

    std::cout << "Success!" << std::endl;

    return 0;
}

bool InitTokenEx()
{
    HMODULE module = NULL_PTR;
    CK_SESSION_HANDLE session = NULL_PTR;
    CK_FUNCTION_LIST_PTR function_list = NULL_PTR;
    CK_C_GetFunctionList get_function_list_func = NULL_PTR;
    CK_FUNCTION_LIST_EXTENDED_PTR function_list_ex = NULL_PTR;
    CK_C_EX_GetFunctionListExtended get_function_list_func_ex = NULL_PTR;
    CK_SLOT_ID_PTR slots = NULL_PTR;
    CK_ULONG slot_count = 0;

    CK_RV rv = CKR_OK;

    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    if (module == NULL_PTR)
    {
        std::cout << "Function 'LoadLibrary' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    get_function_list_func = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    if (get_function_list_func == NULL_PTR)
    {
        std::cout << "Function 'GetProcAddress' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    rv = get_function_list_func(&function_list);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_GetFunctionList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    get_function_list_func_ex = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module, "C_EX_GetFunctionListExtended");
    if (get_function_list_func == NULL_PTR)
    {
        std::cout << "Function 'GetProcAddress' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    rv = get_function_list_func(&function_list);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_GetFunctionList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = get_function_list_func_ex(&function_list_ex);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'CK_C_EX_GetFunctionList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_Initialize(NULL_PTR);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_Initialize' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_GetSlotList(CK_TRUE, NULL_PTR, &slot_count);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_GetSlotList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    if (slot_count == 0)
    {
        std::cout << "Function 'C_GetSlotList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    slots = (CK_SLOT_ID*)malloc(slot_count * sizeof(CK_SLOT_ID));
    memset(slots, 0, (slot_count * sizeof(CK_SLOT_ID)));

    rv = function_list->C_GetSlotList(CK_TRUE, slots, &slot_count);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_GetSlotList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    static CK_UTF8CHAR NEW_USER_PIN[] = {'1', '2', '3', '4', '5', '6', '7', '8'};
    static CK_UTF8CHAR SO_PIN[] = {'8', '7', '6', '5', '4', '3', '2', '1'};
    static CK_CHAR TOKEN_STD_LABEL[] = {"!!!Sample Rutoken label!!!"};

    CK_RUTOKEN_INIT_PARAM initInfo_st;
    CK_BBOOL bIsRutokenECP = TRUE;

    ::memset(&initInfo_st, 0, sizeof(CK_RUTOKEN_INIT_PARAM));

    initInfo_st.ulSizeofThisStructure = sizeof(CK_RUTOKEN_INIT_PARAM);
    initInfo_st.UseRepairMode = 0;
    initInfo_st.pNewAdminPin = SO_PIN;
    initInfo_st.ulNewAdminPinLen = sizeof(SO_PIN);
    initInfo_st.pNewUserPin = NEW_USER_PIN;
    initInfo_st.ulNewUserPinLen = sizeof(NEW_USER_PIN);
    initInfo_st.ulMinAdminPinLen = bIsRutokenECP ? 6 : 1;
    initInfo_st.ulMinUserPinLen = bIsRutokenECP ? 6 : 1;
    initInfo_st.ChangeUserPINPolicy = (TOKEN_FLAGS_ADMIN_CHANGE_USER_PIN | TOKEN_FLAGS_USER_CHANGE_USER_PIN);
    initInfo_st.ulMaxAdminRetryCount = MAX_ADMIN_RETRY_COUNT;
    initInfo_st.ulMaxUserRetryCount = MAX_USER_RETRY_COUNT;
    initInfo_st.pTokenLabel = TOKEN_STD_LABEL;
    initInfo_st.ulLabelLen = sizeof(TOKEN_STD_LABEL);

    rv = function_list_ex->C_EX_InitToken(slots[0], SO_PIN, arraysize(SO_PIN), &initInfo_st);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_EX_InitToken' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_CloseAllSessions(slots[0]);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_CloseAllSessions' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    return true;
}

bool InitToken()
{
    HMODULE module = NULL_PTR;
    CK_SESSION_HANDLE session = NULL_PTR;

    CK_FUNCTION_LIST_PTR function_list = NULL_PTR;
    CK_C_GetFunctionList get_function_list_func = NULL_PTR;

    CK_SLOT_ID_PTR slots = NULL_PTR;
    CK_ULONG slot_count = 0;

    CK_RV rv = CKR_OK;

    module = LoadLibrary(PKCS11_LIBRARY_NAME);
    if (module == NULL_PTR)
    {
        std::cout << "Function 'LoadLibrary' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    get_function_list_func = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    if (get_function_list_func == NULL_PTR)
    {
        std::cout << "Function 'GetProcAddress' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    rv = get_function_list_func(&function_list);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_GetFunctionList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_Initialize(NULL_PTR);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_Initialize' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_GetSlotList(CK_TRUE, NULL_PTR, &slot_count);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_GetSlotList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    if (slot_count == 0)
    {
        std::cout << "Function 'C_GetSlotList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    slots = (CK_SLOT_ID*)malloc(slot_count * sizeof(CK_SLOT_ID));
    memset(slots, 0, (slot_count * sizeof(CK_SLOT_ID)));

    rv = function_list->C_GetSlotList(CK_TRUE, slots, &slot_count);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_GetSlotList' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_InitToken(slots[0], SO_PIN, sizeof(SO_PIN), TOKEN_LABEL);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_InitToken' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_OpenSession' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_Login(session, CKU_SO, SO_PIN, sizeof(SO_PIN));
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_OpenSession' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_InitPIN(session, USER_PIN, sizeof(USER_PIN));
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_OpenSession' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_Logout(session);
    if ((rv != CKR_OK) && (rv != CKR_USER_NOT_LOGGED_IN))
    {
        std::cout << "Function 'C_Logout' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    rv = function_list->C_CloseAllSessions(slots[0]);
    if (rv != CKR_OK)
    {
        std::cout << "Function 'C_CloseAllSessions' failed! Error: 0x" << std::hex << rv << std::endl;
        return false;
    }

    return true;
}

bool DeleteContainer(LPCSTR container_name, LPCSTR reader_name)
{
    std::string full_container_name = std::string(reader_name) + std::string(container_name);
    HCRYPTPROV prov = 0;

    if (!::CryptAcquireContext(&prov, reader_name, g_prov_name, g_prov_type, CRYPT_DEFAULT_CONTAINER_OPTIONAL | CRYPT_SILENT))
    {
        std::cout << "Function 'CryptAcquireContext' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    if (!::CryptSetProvParam(prov, PP_KEYEXCHANGE_PIN, (BYTE*)g_token_pass, 0))
    {
        std::cout << "Function 'CryptSetProvParam' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    HCRYPTPROV prov2 = 0;
    if (!::CryptAcquireContext(&prov2, full_container_name.c_str(), g_prov_name, g_prov_type, CRYPT_SILENT | CRYPT_DELETEKEYSET))
    {
        std::cout << "Function 'CryptAcquireContext' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    ::CryptReleaseContext(prov2, 0);
    ::CryptReleaseContext(prov, 0);

    return true;
}

bool GenerateKeyPair(LPCSTR container_name, LPCSTR reader_name)
{
    std::string full_container_name = std::string(reader_name) + std::string(container_name);
    HCRYPTPROV prov = 0;

    if (!::CryptAcquireContext(&prov, reader_name, g_prov_name, g_prov_type, CRYPT_DEFAULT_CONTAINER_OPTIONAL | CRYPT_SILENT))
    {
        std::cout << "Function 'CryptAcquireContext' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    if (!::CryptSetProvParam(prov, PP_KEYEXCHANGE_PIN, (BYTE*)g_token_pass, 0))
    {
        std::cout << "Function 'CryptSetProvParam' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    HCRYPTPROV prov2 = 0;
    HCRYPTKEY key = 0;

    if (!::CryptAcquireContext(&prov2, full_container_name.c_str(),    g_prov_name, g_prov_type, CRYPT_NEWKEYSET | CRYPT_SILENT))
    {
        std::cout << "Function 'CryptAcquireContext' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    if (!::CryptGenKey(prov2, AT_KEYEXCHANGE, 0, &key))
    {
        std::cout << "Function 'CryptGenKey' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    ::CryptDestroyKey(key);
    key = 0;

    if (!::CryptGetUserKey(prov2, AT_KEYEXCHANGE, &key))
    {
        std::cout << "Function 'CryptGetUserKey' failed! Error: 0x" << std::hex << HRESULT_FROM_WIN32(::GetLastError()) << std::endl;
        return false;
    }

    ::CryptDestroyKey(key);
    ::CryptReleaseContext(prov2, 0);
    ::CryptReleaseContext(prov, 0);

    return true;
}

Re: Не удаляется контейнер 'Aktiv ruToken CSP v1.0' на Rutoken Lite

Я использую функцию C_EX_InitToken из библиотеки rtPKCS11ECP.dll, как указано в тесте. Запустите тест и вы увидите, что проблема не в том, что инициализация не проходит, а в том, что провайдер не может своими функциями удалить свой же контейнер. Очевидно, что у вас что-то сломалось на драйверах начиная с версии v.2.100.00.0542_20.11.2014. На более ранних версиях драйверов пример будет работать.

Re: Не удаляется контейнер 'Aktiv ruToken CSP v1.0' на Rutoken Lite

Мда, простите, вообще неправильно понял, о чем вы пишете.
Теперь понятно - будем смотреть.

Re: Не удаляется контейнер 'Aktiv ruToken CSP v1.0' на Rutoken Lite

Спасибо за ваш репорт. Ошибку нашли.
В следующей версии библиотеки pkcs11ecp будет исправлено.