Для использования API подключите к проекту заголовочный файл jcPKCS11.h
.
Пример:
#include "jcPKCS11.h"
Прилинкуйте библиотеку к проекту.
вызовите функцию C_GetFunctionList()
для получения функций стандарта PKCS #11,
реализованных в библиотеке. Все они описаны в разделе Функции, входящие в стандарт PKCS #11;
Пример:
/// ...
// Список функций, входящих в стандарт PKCS #11
CK_FUNCTION_LIST_PTR funcs = NULL_PTR;
// Загрузить функцию для получения списка функций, входящих в стандарт PKCS #11
CK_C_GetFunctionList C_GetFunctionList = (CK_C_GetFunctionList) GetFunction(libHandle, "C_GetFunctionList");
if (C_GetFunctionList == NULL_PTR)
{
printf("ERROR: C_GetFunctionList hasn't been found in module\n");
return;
}
// Загрузить функции, входящие в стандарт PKCS #11
rv = C_GetFunctionList(&funcs);
if (rv != CKR_OK)
{
printf("ERROR: C_GetFunctionList is failed: 0x%08x\n", rv);
return;
}
printf("C_GetFunctionList - OK\n");
/// ...
// Использование на примере инициализации библиотеки
rv = funcs->C_Initialize(NULL_PTR);
if (rv != CKR_OK)
{
printf("ERROR: C_Initialize is failed: 0x%08x\n", rv);
return;
}
printf("C_Initialize - OK\n");
/// ...
вызовите функцию JC_GetFunctionList()
для получения дополнительных функций,
реализованных в библиотеке, но не входящих в стандарт PKCS #11.
Все они описаны в разделе Функции, не входящие в стандарт PKCS #11.
Этот шаг следует выполнять, если Вам требуются функции расширения.
Пример:
/// ...
// Список дополнительных функций, не входящих в стандарт PKCS #11
JC_FUNCTION_LIST_PTR funcsExtra = NULL_PTR;
// Загрузить функцию для получения списка дополнительных функций, не входящих в стандарт PKCS #11
FP_JC_GetFunctionList JC_GetFunctionList = (FP_JC_GetFunctionList) GetFunction(libHandle, "JC_GetFunctionList");
if (JC_GetFunctionList == NULL_PTR)
{
printf("ERROR: C_GetFunctionList hasn't been found in module\n");
return;
}
// Загрузить дополнительные функции, не входящие в стандарт PKCS #11
rv = JC_GetFunctionList(&funcsExtra);
if (rv != CKR_OK)
{
printf("ERROR: JC_GetFunctionList is failed: 0x%08x\n", rv);
return;
}
printf("JC_GetFunctionList - OK\n");
/// ...
// Использование на примере получения версии библиотеки jcPKCS11-2
JC_VERSION_INFO versionInfo;
CK_RV rv = funcsExtra->JC_GetVersionInfo(&versionInfo);
if (rv != CKR_OK)
{
printf("ERROR: JC_GetVersionInfo is failed: 0x%08x\n", rv);
return;
}
printf("JC_GetVersionInfo - OK\n");
/// ...
Совет
В разделе Базовый пример представлена полная реализация алгоритма с использованием динамической библиотеки jcPKCS11-2.
Рассмотрим каждый шаг более подробно:
Проинициализируйте библиотеку.
Перед началом работы необходимо проинициализировать
библиотеку при помощи функции C_Initialize()
.
Ее всегда необходимо вызывать перед вызовом остальных функций.
Важно
Нельзя вызывать C_Initialize()
несколько раз
подряд без предварительного завершения работы с ней
(см. шаг 4 данного раздела).
Пример:
CK_RV rv = CKR_OK;
// Проинициализировать библиотеку
rv = C_Initialize(NULL_PTR);
if (rv != CKR_OK)
{
printf("ERROR: C_Initialize is failed: 0x%08x\n", rv);
return;
}
printf("C_Initialize - OK\n");
/// ...
Определите слот для дальнейшей работы.
После инициализации библиотеки необходимо определить слот апплета (см. Работа с апплетами), с которым в дальнейшем будете работать.
2.1. Получите список доступных слотов при помощи функции C_GetSlotList()
.
Пример:
/// ... // Массив слотов CK_SLOT_ID_PTR slots = NULL; // Размер массива слотов CK_ULONG slotsCount = 0; // Получите список доступных слотов // Получить кол-во слотов с подключенными апплетами // и Антифрод-терминалы без вставленной смарт-карты rv = C_GetSlotList(CK_TRUE, NULL, &slotsCount); if(rv != CKR_OK) { printf("ERROR: C_GetSlotList first call is failed: 0x%08x\n", rv); return; } printf("C_GetSlotList first call (slotsCount: %d) - OK\n", slotsCount); // Есть ли слоты? if(slotsCount == 0) { printf("ERROR: JaCarta smartcards haven't been found.\n"); return; } // Выделить память под массив слотов размером - slotsCount slots = (CK_SLOT_ID_PTR) malloc(sizeof(CK_SLOT_ID) * slotsCount); if(slots == NULL_PTR) { printf("ERROR: Memory issue.\n"); return; } // Заполнить массив слотов rv = C_GetSlotList(CK_TRUE, slots, &slotsCount); if(rv != CKR_OK) { printf("ERROR: C_GetSlotList second call is failed: 0x%08x\n", rv); free(slots); return; } printf("C_GetSlotList second call - OK\n"); /// ... /// После заврешения работы с slots не забудьте очистить память: /// free(slots);
2.2. Выберите необходимый апплет.
Для выбора апплета необходимо для каждого слота вызвать функцию
C_GetTokenInfo()
и в полученной информации об апплете сравнить название модели (аргументCK_TOKEN_INFO.model
) с интересующим названием модели апплета:
JC_MODEL_CRYPTOTOKEN_2
– для апплета Криптотокен 2 ЭП;JC_MODEL_CRYPTOTOKEN_1
– для апплета Криптотокен;JC_MODEL_LASER
– для апплета Laser;JC_MODEL_DATASTORE
– для апплета Datastore;JC_MODEL_PRO
– для апплета PRO.Пример:
/// ... // Выбираемый слот CK_SLOT_ID slotID; // Наименование необходимого апплета. // В данном случае ищем апплет "Криптотокен 2 ЭП". const char* modelName = JC_MODEL_CRYPTOTOKEN_2; // Длина наименования необходимого апплета size_t modelLength = strlen(modelName); CK_BBOOL slotFound = CK_FALSE; for (CK_ULONG i = 0; i < slotsCount; ++i) { CK_SLOT_ID tmpSlotID = slots[i]; CK_TOKEN_INFO tokenInfo = {}; // Получить информацию о токене в слоте rv = C_GetTokenInfo(tmpSlotID, &tokenInfo); if(rv != CKR_OK) { continue; } printf("C_GetTokenInfo (slotID: %lu) - OK\n", tmpSlotID); // Поиск модели апплета, совпадающей с modelName int res = !memcmp((const char*)tokenInfo.model, modelName, modelLength); if (res == 0) { slotID = tmpSlotID; slotFound = CK_TRUE; break; } } /// Если slots больше не нужен, то очистите память: /// free(slots); if(slotFound == CK_FALSE) { printf("ERROR: Slot hasn't been found\n"); } else { printf("Slot has been found: %d\n", slotID); } /// ...
Завершите работу с библиотекой.
Для завершения работы вызовите функцию C_Finalize()
.
Пример:
/// ...
rv = C_Finalize(NULL_PTR);
if (rv != CKR_OK)
{
printf("ERROR: C_Finalize is failed: 0x%08x\n", rv);
return;
}
printf("C_Finalize - OK\n");
В большинстве случаев работа с апплетом происходит через зашифрованный сеанс. Перед открытием зашифрованного сеанса выберите слот, на котором он будет открыт (см. шаг 2 в разделе Общий алгоритм использования).
Совет
В разделе Базовый пример представлена полная реализация алгоритма с использованием динамической библиотеки jcPKCS11-2.
Жизненный цикл зашифрованного сеанса:
Откройте зашифрованный сеанс.
Для этого вызовите функцию C_OpenSession()
и передайте ей
выбранный ранее слот. В случае успешного выполнения,
функция вернет идентификатор зашифрованного сеанса.
Пример:
/// ...
// Открываемая сессия
CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
// Откройте зашифрованный сеанс
rv = C_OpenSession(slotID, (CKF_SERIAL_SESSION | CKF_RW_SESSION), NULL_PTR, NULL_PTR, &session);
if(rv != CKR_OK)
{
printf("ERROR: C_OpenSession (slotID: %d) is failed: 0x%08x\n", slotID, rv);
return;
}
printf("C_OpenSession (slotID: %d) - OK\n", slotID);
printf("session : %d\n", session);
/// ...
Для работы с апплетом внутри сеанса используйте идентификатор этого сеанса, полученного на шаге 1.
Пример: Предъявление PIN-кода пользователя и сброс предъявления
/// ...
// PIN-код пользователя
CK_CHAR pin[] = "1234567890";
// Предъявить PIN-код пользователя
rv = C_Login(session, CKU_USER, (CK_CHAR_PTR)pin, (CK_ULONG)strlen((const char*)pin));
if (rv != CKR_OK)
{
printf("ERROR: C_Login is failed: 0x%08x\n", rv);
}
else
{
printf("C_Login - OK\n");
// Сбросить предъявление PIN-кода пользователя
rv = C_Logout(session);
if(rv != CKR_OK)
{
printf("ERROR: C_Logout is failed: 0x%08x\n", rv);
}
else
{
printf("C_Logout - OK\n");
}
}
/// ...
C_CloseSession()
и передайте ей идентификатор сеанса, полученного на шаге 1.C_CloseAllSessions()
.Пример:
/// ...
// Закрыть сессию
rv = C_CloseSession(session);
if(rv != CKR_OK)
{
printf("ERROR: C_CloseSession is failed: 0x%08x\n", rv);
}
else
{
printf("C_CloseSession - OK\n");
}
/// ...
Примечание
Один слот может иметь несколько одновременно открытых сеансов.
Каждый объект, хранящийся на устройстве JaCarta (или в оперативной памяти ОС), имеет атрибуты, которые в совокупности задают свойства объекта. Атрибуты задают тип объекта, его видимость, его местоположение и т. д.
Примечание
В библиотеке jcPKCS11-2 поддерживаются сертификаты открытого ключа только формата X.509.
CKO_MECHANISM
;CKO_VENDOR_DEFINED
;CKO_HW_FEATURE
.Подробнее о работе с объектами и их свойствах указано в разделе Объекты PKCS #11.