Пример демонстрирует базовое использование библиотеки jcPKCS11-2, описанное в разделе Работа с библиотекой.
C_GetInfo()
,
входящей в состав PKCS #11 (см. ф-цию sample_getLibraryInfo);JC_GetVersionInfo()
,
не входящей в состав PKCS #11 (см. ф-цию sample_getJcPKCS11Version);Приложение, реализующее данные требования, носит название jcPKCS11Sample
и имеет следующую файловую структуру
jcPKCS11/lib
– директория, содержащая динамические библиотеки
jcPKCS11-2 под различные платформы;jcPKCS11/include
– директория, содержащая заголовочные файлы jcPKCS11-2.main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#ifdef WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include "jcPKCS11/jcPKCS11.h"
/** Вспомогательные макросы под различные ОС
*/
#ifdef WIN32
// Windows
// Тип указателя на библиотеку
#define LibraryHandle HMODULE
// Функция загрузки динамической библиотеки
#define LoadSharedLibrary LoadLibraryA
// Функция выгрузки динамической библиотеки
#define FreeSharedLibrary FreeLibrary
// Функция получения указателя на функцию из библиотеки
inline void * GetFunction(HMODULE hDll, const char * pFunctionName)
{
return GetProcAddress(hDll, pFunctionName);
}
#else
// macOS, Linux
// Тип указателя на библиотеку
#define LibraryHandle void*
// Функция загрузки динамической библиотеки
inline void * LoadSharedLibrary(const char* pFileName)
{
return dlopen(pFileName, RTLD_LAZY);
}
// Функция выгрузки динамической библиотеки
#define FreeSharedLibrary dlclose
// Функция получения указателя на функцию из библиотеки
#define GetFunction dlsym
#endif
// Объявление функций
void usingJcPKCS11(LibraryHandle libHandle);
void sample_getLibraryInfo(CK_FUNCTION_LIST_PTR funcs);
void sample_getJcPKCS11Version(JC_FUNCTION_LIST_PTR funcsExtra);
CK_BBOOL sample_getSlotID(CK_FUNCTION_LIST_PTR funcs, CK_SLOT_ID* slotID);
void sample_session(CK_SLOT_ID slotID, CK_FUNCTION_LIST_PTR funcs);
/**
*/
int main (int argc, char *argv[])
{
// Подгрузить динамическую библиотеку
printf("Trying to load %s ...\n", JC_PKCS_LIB_PATH);
LibraryHandle libHandle = LoadSharedLibrary(JC_PKCS_LIB_PATH);
if (libHandle == NULL)
{
printf("ERROR: Library hasn't been loaded.\n");
return 1;
}
printf("DONE\n\n");
// Пример использования библиотеки jcPKCS11
usingJcPKCS11(libHandle);
printf("\n");
// Выгрузить динамическую библиотеку
printf("Trying to free the library ...\n");
FreeSharedLibrary(libHandle);
printf("DONE\n\n");
printf("The end\n");
return 0;
}
/** Пример использования jcPKCS11-2
*/
void usingJcPKCS11(LibraryHandle libHandle)
{
CK_RV rv = CKR_OK;
// 1. Загрузить функции, входящие в стандарт PKCS #11
// Список функций, входящих в стандарт PKCS #11
CK_FUNCTION_LIST_PTR funcs = NULL_PTR;
// 1.1. Загрузить функцию для получения списка функций, входящих в стандарт 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;
}
// 1.2. Загрузить функции, входящие в стандарт PKCS #11
rv = C_GetFunctionList(&funcs);
if (rv != CKR_OK)
{
printf("ERROR: C_GetFunctionList is failed: 0x%08lu\n", rv);
return;
}
printf("C_GetFunctionList - OK\n");
// 2. Загрузить дополнительные функции, не входящие в стандарт PKCS #11
// Список дополнительных функций, не входящих в стандарт PKCS #11
JC_FUNCTION_LIST_PTR funcsExtra = NULL_PTR;
// 2.1. Загрузить функцию для получения списка дополнительных функций, не входящих в стандарт 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;
}
// 2.2. Загрузить дополнительные функции, не входящие в стандарт PKCS #11
rv = JC_GetFunctionList(&funcsExtra);
if (rv != CKR_OK)
{
printf("ERROR: JC_GetFunctionList is failed: 0x%08lu\n", rv);
return;
}
printf("JC_GetFunctionList - OK\n");
printf("\n");
// 3. Проинициализировать библиотеку
rv = funcs->C_Initialize(NULL_PTR);
if (rv != CKR_OK)
{
printf("ERROR: C_Initialize is failed: 0x%08lu\n", rv);
return;
}
printf("C_Initialize - OK\n");
printf("\n");
// 4. Примеры использования
sample_getLibraryInfo(funcs);
printf("\n");
sample_getJcPKCS11Version(funcsExtra);
printf("\n");
CK_SLOT_ID slotID;
if (sample_getSlotID(funcs, &slotID) == CK_TRUE)
{
printf("\n");
sample_session(slotID, funcs);
printf("\n");
}
// 5. Завершить работу с библиотекой
rv = funcs->C_Finalize(NULL_PTR);
if (rv != CKR_OK)
{
printf("ERROR: C_Finalize is failed: 0x%08lu\n", rv);
return;
}
printf("C_Finalize - OK\n");
}
/** Получить информацию о библиотеке PKCS #11
при помощи функции C_GetInfo,
входящей в стандарт PKCS #11.
*/
void sample_getLibraryInfo(CK_FUNCTION_LIST_PTR funcs)
{
printf("sample_getLibraryInfo:\n");
CK_INFO libraryInfo;
CK_RV rv = funcs->C_GetInfo(&libraryInfo);
if (rv != CKR_OK)
{
printf("ERROR: C_GetInfo is failed: 0x%08lu\n", rv);
return;
}
printf("C_GetInfo - OK\n");
printf("PKCS #11 revision : %i.%i\n",
(int)libraryInfo.cryptokiVersion.major,
(int)libraryInfo.cryptokiVersion.minor);
printf("Manufacturer : %.32s\n",
libraryInfo.manufacturerID);
printf("Description : %.32s\n",
libraryInfo.libraryDescription);
printf("Library version : %i.%i\n",
(int)libraryInfo.libraryVersion.major,
(int)libraryInfo.libraryVersion.minor);
}
/** Получить версию библиотеки jcPKCS11-2
при помощи функции JC_GetVersionInfo,
не входящей в стандарт PKCS #11.
*/
void sample_getJcPKCS11Version(JC_FUNCTION_LIST_PTR funcsExtra)
{
printf("sample_getJcPKCS11Version:\n");
JC_VERSION_INFO versionInfo;
CK_RV rv = funcsExtra->JC_GetVersionInfo(&versionInfo);
if (rv != CKR_OK)
{
printf("ERROR: JC_GetVersionInfo is failed: 0x%08lu\n", rv);
return;
}
printf("JC_GetVersionInfo - OK\n");
printf("jcPKCS11 version : %lu.%lu.%lu.%lu\n",
versionInfo.ulMajor,
versionInfo.ulMinor,
versionInfo.ulRelease,
versionInfo.ulBuild);
}
/** Получить идентификатор слота
*/
CK_BBOOL sample_getSlotID(CK_FUNCTION_LIST_PTR funcs, CK_SLOT_ID* slotID)
{
printf("sample_getSlotID:\n");
CK_RV rv = CKR_OK;
// Массив слотов
CK_SLOT_ID_PTR slots = NULL;
// Размер массива слотов
CK_ULONG slotsCount = 0;
// Получить кол-во слотов с подключенными апплетами
// и Антифрод-терминалы без вставленной смарт-карты
rv = funcs->C_GetSlotList(CK_TRUE, NULL, &slotsCount);
if(rv != CKR_OK)
{
printf("ERROR: C_GetSlotList first call is failed: 0x%08lu\n", rv);
return CK_FALSE;
}
printf("C_GetSlotList first call (slotsCount: %lu) - OK\n", slotsCount);
// Есть ли слоты?
if(slotsCount == 0)
{
printf("ERROR: JaCarta smartcards haven't been found.\n");
return CK_FALSE;
}
// Выделить память под массив слотов размером - slotsCount
slots = (CK_SLOT_ID_PTR) malloc(sizeof(CK_SLOT_ID) * slotsCount);
if(slots == NULL_PTR)
{
printf("ERROR: Memory issue.\n");
return CK_FALSE;
}
// Заполнить массив слотов
rv = funcs->C_GetSlotList(CK_TRUE, slots, &slotsCount);
if(rv != CKR_OK)
{
printf("ERROR: C_GetSlotList second call is failed: 0x%08lu\n", rv);
free(slots);
return CK_FALSE;
}
printf("C_GetSlotList second call - OK\n");
// Выбор необходимого апплета
// Наименование необходимого апплета.
// В данном случае ищем апплет "Криптотокен 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 = funcs->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;
}
}
// Очистить память
free(slots);
if(slotFound == CK_FALSE)
{
printf("ERROR: Slot hasn't been found\n");
}
else
{
printf("Slot has been found: %lu\n", *slotID);
}
return slotFound;
}
/** Пример работы с зашифрованным сеансом.
*/
void sample_session(CK_SLOT_ID slotID, CK_FUNCTION_LIST_PTR funcs)
{
printf("sample_session:\n");
CK_RV rv = CKR_OK;
// PIN-код пользователя
CK_CHAR pin[] = "1234567890";
// Открываемая сессия
CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
// Откройте зашифрованный сеанс
rv = funcs->C_OpenSession(slotID, (CKF_SERIAL_SESSION | CKF_RW_SESSION), NULL_PTR, NULL_PTR, &session);
if(rv != CKR_OK)
{
printf("ERROR: C_OpenSession (slotID: %lu) is failed: 0x%08lu\n", slotID, rv);
return;
}
printf("C_OpenSession (slotID: %lu) - OK\n", slotID);
printf("session : %lu\n", session);
// Предъявить PIN-код пользователя
rv = funcs->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%08lu\n", rv);
}
else
{
printf("C_Login - OK\n");
// Сбросить предъявление PIN-кода пользователя
rv = funcs->C_Logout(session);
if(rv != CKR_OK)
{
printf("ERROR: C_Logout is failed: 0x%08lu\n", rv);
}
else
{
printf("C_Logout - OK\n");
}
}
// Закрыть сессию
rv = funcs->C_CloseSession(session);
if(rv != CKR_OK)
{
printf("ERROR: C_CloseSession is failed: 0x%08lu\n", rv);
}
else
{
printf("C_CloseSession - OK\n");
}
}
CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(jcPKCS11Sample)
if(MSVC)
SET(JC_OS "Win")
if ("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
SET(JC_OS_BITNESS "64")
else()
SET(JC_OS_BITNESS "32")
endif()
elseif(APPLE)
SET(JC_OS "Apple")
else()
SET(JC_OS "Linux")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
SET(JC_OS_BITNESS "64")
else()
SET(JC_OS_BITNESS "32")
endif()
endif()
message(STATUS "JC_OS: ${JC_OS}")
message(STATUS "JC_OS_BITNESS: ${JC_OS_BITNESS}")
get_filename_component(JC_PROJECT_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
if(${JC_OS} MATCHES "Win")
set(JC_FLAGS "/wd4514 /wd4710 /wd4820 /wd4350 /wd4668 /wd4711 /wd4365 /wd4100")
set(JC_DEFINITIONS "-DCK_Win32 -D_CRT_SECURE_NO_WARNINGS")
if(${JC_OS_BITNESS} MATCHES "64")
set(JC_PKCS_LIB_PATH "${JC_PROJECT_DIR}/jcPKCS11/lib/Win64/jcPKCS11-2.dll")
set(JC_BIN_DIR "${JC_PROJECT_DIR}/_bin/Win/x64")
else()
set(JC_PKCS_LIB_PATH "${JC_PROJECT_DIR}/jcPKCS11/lib/Win32/jcPKCS11-2.dll")
set(JC_BIN_DIR "${JC_PROJECT_DIR}/_bin/Win/x86")
endif()
elseif("${JC_OS}" MATCHES "Apple")
set(JC_FLAGS "-Wno-write-strings -fpermissive")
set(JC_PKCS_LIB_PATH "${JC_PROJECT_DIR}/jcPKCS11/lib/macOS/jcPKCS11-2")
set(JC_BIN_DIR "${JC_PROJECT_DIR}/_bin/macOS")
elseif("${JC_OS}" MATCHES "Linux")
set(JC_FLAGS "-Wno-write-strings -fpermissive")
if(${JC_OS_BITNESS} MATCHES "64")
set(JC_PKCS_LIB_PATH "${JC_PROJECT_DIR}/jcPKCS11/lib/linux-x86_64/libjcPKCS11-2.so")
set(JC_BIN_DIR "${JC_PROJECT_DIR}/_bin/linux/x86_64")
else()
set(JC_PKCS_LIB_PATH "${JC_PROJECT_DIR}/jcPKCS11/lib/linux-i386/libjcPKCS11-2.so")
set(JC_BIN_DIR "${JC_PROJECT_DIR}/_bin/linux/i386")
endif()
else()
message(FATAL_ERROR "Unknown operation system")
endif()
message(STATUS "JC_PKCS_LIB_PATH: ${JC_PKCS_LIB_PATH}")
message(STATUS "JC_BIN_DIR: ${JC_BIN_DIR}")
message(STATUS "JC_FLAGS: ${JC_FLAGS}")
message(STATUS "JC_DEFINITIONS: ${JC_DEFINITIONS}")
add_definitions("-Wall")
add_definitions("-DJC_PKCS_LIB_PATH=\"${JC_PKCS_LIB_PATH}\"")
add_definitions("${JC_FLAGS}")
add_definitions("${JC_DEFINITIONS}")
include_directories("${JC_PROJECT_DIR}/jcPKCS11/include")
set(SOURCES src/main.cpp)
add_executable(jcPKCS11Sample ${SOURCES})
if(${JC_OS} MATCHES "Win")
target_link_libraries(jcPKCS11Sample "Ws2_32.lib")
elseif(${JC_OS} MATCHES "Linux")
target_link_libraries(jcPKCS11Sample dl)
endif()
set_target_properties(jcPKCS11Sample PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${JC_BIN_DIR}")
make.bat:
@echo off
if not exist ./_out md _out
cd _out
cmake ..
if %ERRORLEVEL% GTR 0 exit /b %ERRORLEVEL%
cmake --build . --config Debug
if %ERRORLEVEL% GTR 0 exit /b %ERRORLEVEL%
cd ..
make.sh:
#!/bin/bash
if [ ! -d _out ]; then
mkdir _out
fi
cd _out
cmake -G "Unix Makefiles" .. || exit 1
cmake --build . --config Debug || exit 1
cd ..