Page tree

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

Полный список примеров, который есть в комплекте SDK (/pkcs/samples): 

Перед запуском примеров необходимо отформатировать Рутокен БИО.

Сделать это можно в Центре управления Рутокен (статьи про форматирование на Windows и Linux) или с помощью функции C_EX_InitToken.

Рекомендуется запускать примеры в том порядке, в котором они представлены в документе.

Иной порядок запуска может вызвать ошибки.

Вспомогательные файлы

Файл win2nix.h. Переопределение функций Windows для *nix-платформ
#pragma once

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _WIN32
    #include <windows.h>

typedef HANDLE mutex_t;
#else
    #include <pthread.h>

    #define uintptr_t pthread_t

typedef pthread_mutex_t mutex_t;
#endif

typedef struct {
    void (*func)(void*);
    void* arg;
} thread_args;



static
#ifdef _WIN32
    unsigned __stdcall
#else
    void*
#endif
    wrapperRunner(void* arg) {
    thread_args* th = (thread_args*)arg;
    th->func(th->arg);
    free(th);
#ifdef _WIN32
    _endthreadex(0);
    return 0;
#else
    return NULL;
#endif
}

static int createThread(uintptr_t* thread, void (*funct)(void*), void* arg) {
    thread_args* th = (thread_args*)malloc(sizeof(thread_args));

    if (th == NULL) {
        return 1;
    }

    th->arg = arg;
    th->func = funct;
#ifdef _WIN32
    *thread = _beginthreadex(NULL, 0, wrapperRunner, th, 0, NULL);
    if (*thread == 0)
#else
    if (pthread_create(thread, NULL, wrapperRunner, th))
#endif
    {
        free(th);
        return 1;
    }

    return 0;
}

static int joinThread(uintptr_t thread) {
#ifdef _WIN32
    DWORD rv1 = WaitForSingleObject((HANDLE)thread, INFINITE);
    int rv = !CloseHandle((HANDLE)thread) || rv1;
#else
    int rv = pthread_join(thread, NULL);
#endif
    return !!rv;
}

static int createMutex(mutex_t* mutex) {
#ifdef _WIN32
    *mutex = CreateMutex(NULL, FALSE, NULL);
    if (!*mutex) {
        return 1;
    }
#else
    if (pthread_mutex_init(mutex, NULL)) {
        return 1;
    }
#endif
    return 0;
}

static int destroyMutex(mutex_t* mutex) {
#ifdef _WIN32
    if (!CloseHandle(*mutex)) {
        return 1;
    }
#else
    if (pthread_mutex_destroy(mutex)) {
        return 1;
    }
#endif
    return 0;
}

static int lockMutex(mutex_t* mutex) {
#ifdef _WIN32
    if (WaitForSingleObject(*mutex, INFINITE) != WAIT_OBJECT_0) {
        return 1;
    }
#else
    if (pthread_mutex_lock(mutex)) {
        return 1;
    }
#endif
    return 0;
}

static int unlockMutex(mutex_t* mutex) {
#ifdef _WIN32
    if (!ReleaseMutex(*mutex)) {
        return 1;
    }
#else
    if (pthread_mutex_unlock(mutex)) {
        return 1;
    }
#endif
    return 0;
}

#if defined(__unix__) || defined(__APPLE__)

    #include <dlfcn.h>

    #include "wintypes.h"

typedef void* HMODULE;

static HMODULE LoadLibrary(const char* path) {
    return dlopen(path, RTLD_NOW);
}

static BOOL FreeLibrary(HMODULE module) {
    // Возвращаемое значение инвертируется, чтобы соответствовать поведению Windows
    return !dlclose(module);
}

static ptrdiff_t GetProcAddress(HMODULE module, const char* proc_name) {
    return (ptrdiff_t)(dlsym(module, proc_name));
}

#endif // __unix__ || __APPLE__
Файл wintypes.h. Определение типов данных для *nix-платформ
#pragma once

#ifndef DWORD
typedef unsigned long DWORD;
#endif

#ifndef LONG
typedef long LONG;
#endif

#ifndef BYTE
typedef unsigned char BYTE;
#endif

#ifndef BOOL
typedef int BOOL;
#endif

#ifndef PBYTE
typedef BYTE* PBYTE;
#endif

#ifndef LPBYTE
typedef BYTE* LPBYTE;
#endif

#ifndef PVOID
typedef void* PVOID;
#endif

#ifndef IN
    #define IN
#endif

#ifndef OUT
    #define OUT
#endif

Файл Common.h. Объявление констант для работы с Рутокен при помощи библиотеки PKCS#11
на языке C

#ifndef Common_H
#define Common_H
/**************************************************************************
 * Включение файлов:                                                      *
 *  - stdio.h - для доступа к библиотеке стандартного ввода/вывода        *
 *  - Windows.h - для доступа к функциям Win32API                         *
 *  - WinCrypt.h - для доступа к функциям CryptoAPI                       *
 *  - process.h - для доступа к функциям управления потоками и процессами *
 *  - time.h - для доступа к функциям для работы со временем              *
 *  - win2nix.h - для переопределения функций Windows для *nix-платформ   *
 *  - wintypes.h - для переопределения типов данных Windows для           *
 *    *nix-платформ                                                       *
 *  - rtPKCS11.h - для доступа к функциям PKCS#11                         *
 **************************************************************************/
// clang-format off
#ifdef _WIN32
    #include <stdio.h>
    #include <Windows.h>
    #include <WinCrypt.h>
    #include <process.h>
    #include <time.h>
#endif
// clang-format on

#include "win2nix.h"
#include "wintypes.h"

#include <rtpkcs11.h>

#include <stdlib.h>

/************************************************************************
 * Макросы                                                              *
 ************************************************************************/
/* Имя библиотеки PKCS#11 */
#ifdef _WIN32
    /* Библиотека для Рутокен S и Рутокен ЭЦП, поддерживает только алгоритмы RSA */
    #define PKCS11_LIBRARY_NAME "rtPKCS11.dll"
    /* Библиотека только для Рутокен ЭЦП, поддерживает алгоритмы ГОСТ и RSA */
    #define PKCS11ECP_LIBRARY_NAME "rtPKCS11ECP.dll"
#endif
#ifdef __unix__
    /* Библиотека только для Рутокен ЭЦП, поддерживает алгоритмы ГОСТ и RSA */
    #define PKCS11_LIBRARY_NAME "librtpkcs11ecp.so"
    #define PKCS11ECP_LIBRARY_NAME "librtpkcs11ecp.so"
#endif
#ifdef __APPLE__
    /* Библиотека только для Рутокен ЭЦП, поддерживает алгоритмы ГОСТ и RSA */
    #define PKCS11_LIBRARY_NAME "rtpkcs11ecp.framework/rtpkcs11ecp"
    #define PKCS11ECP_LIBRARY_NAME "rtpkcs11ecp.framework/rtpkcs11ecp"
#endif

#ifndef TOKEN_TYPE_RUTOKEN
    #define TOKEN_TYPE_RUTOKEN 0x3
#endif

#ifdef _WIN32
    #define HAVEMSCRYPTOAPI
#endif

/* Вычисление размера массива */
#define arraysize(a) (sizeof(a) / sizeof(a[0]))

/* Максимальный размер массива с дескрипторами */
#define MAX_OBJECTS_ARRAY_SIZE 100

/* Предопределенная константа RSA */
#define RSAENH_MAGIC_RSA1 0x31415352

/* Размер публичного ECDSA ключа в DER формате в байтах */
#define ECDSA_DER_KEY_SIZE 67

/* Размер симметричного ключа в DER формате в байтах */
#define GENERIC_SECRET_KEY_SIZE 64

/* Размер симметричного ключа ГОСТ 28147-89 в байтах */
#define GOST_28147_KEY_SIZE 32

/* Размер открытого ключа ГОСТ Р 34.10-2001 в байтах */
#define GOST_3410_KEY_SIZE 64

/* Размер открытого ключа ГОСТ Р 34.10-2012(256) в байтах */
#define GOST_3410_12_256_KEY_SIZE 64

/* Размер открытого ключа ГОСТ Р 34.10-2012(512) в байтах */
#define GOST_3410_12_512_KEY_SIZE 128

/* Размер симметричного ключа KEG в байтах */
#define KEG_KEY_SIZE 64

/* Размер синхропосылки в байтах */
#define UKM_LENGTH 8

/* Размер UKM для KEG 256 в байтах */
#define UKM_KEG_256_LENGTH 24

/* Размер UKM для KEG 512 в байтах */
#define UKM_KEG_512_LENGTH 16

/* Размер блока в байтах */
#define GOST28147_89_BLOCK_SIZE 8

/* Максимальное количество попыток ввода PIN-кода Администратора */
#define MAX_ADMIN_RETRY_COUNT 10

/* Максимальное количество попыток доступа Пользователя */
#define MAX_USER_RETRY_COUNT 10

/************************************************************************
 * Вспомогательные переменные                                           *
 ************************************************************************/
static CK_BBOOL attributeTrue = CK_TRUE;
static CK_BBOOL attributeFalse = CK_FALSE;

/* Тип сертификата */
static CK_CERTIFICATE_TYPE certificateType = CKC_X_509;

/* Категории сертификата */
static CK_ULONG unspecifiedCertificate = 0;
static CK_ULONG tokenUserCertificate = 1;
static CK_ULONG authorityCertificate = 2;
static CK_ULONG otherEntityCertificate = 3;

/* Длина модуля ключа RSA в битах */
static CK_ULONG rsaModulusBits = 1024;

/* Набор параметров КриптоПро A алгоритма ГОСТ 28147-89 */
static CK_BYTE parametersGost28147[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 };

/* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2001 */
static CK_BYTE parametersGostR3410_2001[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 };

/* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2012(256) */
static CK_BYTE parametersGostR3410_2012_256[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 };

/* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2012(512) */
static CK_BYTE parametersGostR3410_2012_512[] = { 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02,
0x01, 0x02, 0x01 };

/* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-1994 */
static CK_BYTE parametersGostR3411_1994[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 };

/* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(256) */
static CK_BYTE parametersGostR3411_2012_256[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01,
0x02, 0x02 };

/* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(512) */
static CK_BYTE parametersGostR3411_2012_512[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01,
0x02, 0x03 };

/* Параметры для инициализации: разрешается использовать объекты синхронизации операционной системы */
static CK_C_INITIALIZE_ARGS initArgs = { NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR,
CKF_OS_LOCKING_OK, NULL_PTR };

/* Набор параметров для EC */
static CK_BYTE secp256k1Oid[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A };

/* Даты начала и окончания срока действия */
static CK_DATE startDate = { { '2', '0', '2', '0' }, { '1', '2' }, { '2', '5' } };
static CK_DATE endDate = { { '2', '0', '3', '0' }, { '1', '2' }, { '2', '5' } };

/************************************************************************
 * PIN-коды Рутокен                                                     *
 ************************************************************************/
/* DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR USER_PIN[] = { "12345678" };

#define USER_PIN_LEN (sizeof(USER_PIN) - 1)

/* Новый DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR NEW_USER_PIN[] = { "55555555" };

#define NEW_USER_PIN_LEN (sizeof(NEW_USER_PIN) - 1)

/* Новый DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR ALPHABETIC_USER_PIN[] = { "abcdefgh" };

#define ALPHABETIC_USER_PIN_LEN (sizeof(ALPHABETIC_USER_PIN) - 1)

/* Неправильный DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR WRONG_USER_PIN[] = { "00000000" };

#define WRONG_USER_PIN_LEN (sizeof(WRONG_USER_PIN) - 1)

/* DEMO PIN-код Администратора Рутокен */
static CK_UTF8CHAR SO_PIN[] = { "87654321" };

#define SO_PIN_LEN (sizeof(SO_PIN) - 1)

/* DEMO локальный PIN-код Рутокен */
static CK_UTF8CHAR LOCAL_PIN[] = { "1234567890" };

#define LOCAL_PIN_LEN (sizeof(LOCAL_PIN) - 1)

/************************************************************************
 * Описание типов пользователей                                         *
 ************************************************************************/
static CK_USER_TYPE userTypeSO = CKU_SO;
static CK_USER_TYPE userTypeUser = CKU_USER;

/************************************************************************
 * Описание типов объектов                                              *
 ************************************************************************/
static CK_OBJECT_CLASS publicKeyObject = CKO_PUBLIC_KEY;
static CK_OBJECT_CLASS privateKeyObject = CKO_PRIVATE_KEY;
static CK_OBJECT_CLASS secretKeyObject = CKO_SECRET_KEY;
static CK_OBJECT_CLASS certificateObject = CKO_CERTIFICATE;
static CK_OBJECT_CLASS dataObject = CKO_DATA;
static CK_OBJECT_CLASS hardwareFeatureObject = CKO_HW_FEATURE;

/************************************************************************
 * Описание типов ключей                                                *
 ************************************************************************/
static CK_KEY_TYPE keyTypeGeneric = CKK_GENERIC_SECRET;
static CK_KEY_TYPE keyTypeRsa = CKK_RSA;
static CK_KEY_TYPE keyTypeEcdsa = CKK_EC;
static CK_KEY_TYPE keyTypeGost28147 = CKK_GOST28147;
static CK_KEY_TYPE keyTypeGostR3410_2001 = CKK_GOSTR3410;
static CK_KEY_TYPE keyTypeGostR3410_2012_256 = CKK_GOSTR3410;
static CK_KEY_TYPE keyTypeGostR3410_2012_512 = CKK_GOSTR3410_512;
static CK_KEY_TYPE keyTypeKuznechik = CKK_KUZNECHIK;
static CK_KEY_TYPE keyTypeMagma = CKK_MAGMA;
static CK_KEY_TYPE keyTypeKuznechikTwin = CKK_KUZNECHIK_TWIN_KEY;
static CK_KEY_TYPE keyTypeMagmaTwin = CKK_MAGMA_TWIN_KEY;

/************************************************************************
 * Описание типов HW фич                                                *
 ************************************************************************/
static CK_HW_FEATURE_TYPE hardwareFeatureTokenInfo = CKH_VENDOR_TOKEN_INFO;
static CK_HW_FEATURE_TYPE hardwareFeaturePinPolicy = CKH_VENDOR_PIN_POLICY;

/************************************************************************
 * Описание меток объектов                                              *
 ************************************************************************/
/* DEMO-метка открытого ключа RSA */
static CK_UTF8CHAR publicKeyLabelRsa[] = { "Sample RSA Public Key (Aktiv Co.)" };

/* DEMO-метка закрытого ключа RSA */
static CK_UTF8CHAR privateKeyLabelRsa[] = { "Sample RSA Private Key (Aktiv Co.)" };

/* DEMO ID пары ключей RSA */
static CK_BYTE keyPairIdRsa[] = { "RSA sample key pair ID (Aktiv Co.)" };

/* DEMO-метка открытого ключа ECDSA */
static CK_UTF8CHAR publicKeyLabelEcdsa[] = { "Sample ECDSA Public Key (Aktiv Co.)" };

/* DEMO-метка закрытого ключа ECDSA */
static CK_UTF8CHAR privateKeyLabelEcdsa[] = { "Sample ECDSA Private Key (Aktiv Co.)" };

/* DEMO ID пары ключей ECDSA */
static CK_BYTE keyPairIdEcdsa[] = { "ECDSA sample key pair ID (Aktiv Co.)" };

/* DEMO-метка открытого ключа #1 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR publicKeyLabelGost2001_1[] = {
"Sample GOST R 34.10-2001 Public Key 1 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #1 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR privateKeyLabelGost2001_1[] = {
"Sample GOST R 34.10-2001 Private Key 1 (Aktiv Co.)"
};

/* DEMO ID пары ключей #1 ГОСТ Р 34.10-2001 */
static CK_BYTE keyPairIdGost2001_1[] = { "GOST R 34.10-2001 sample key pair 1 ID (Aktiv Co.)" };

/* DEMO-метка открытого ключа #2 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR publicKeyLabelGost2001_2[] = {
"Sample GOST R 34.10-2001 Public Key 2 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #2 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR privateKeyLabelGost2001_2[] = {
"Sample GOST R 34.10-2001 Private Key 2 (Aktiv Co.)"
};

/* DEMO ID пары ключей #2 ГОСТ Р 34.10-2001 */
static CK_BYTE keyPairIdGost2001_2[] = {
"GOST R 34.10-2001 sample key pair 2 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #1 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR publicKeyLabelGost2012_256_1[] = {
"Sample GOST R 34.10-2012 (256 bits) Public Key 1 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #1 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR privateKeyLabelGost2012_256_1[] = {
    "Sample GOST R 34.10-2012 (256 bits) Private Key 1 (Aktiv Co.)"
};

/* DEMO ID пары ключей #1 ГОСТ Р 34.10-2012(256) */
static CK_BYTE keyPairIdGost2012_256_1[] = {
"GOST R 34.10-2012 (256 bits) sample key pair 1 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #2 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR publicKeyLabelGost2012_256_2[] = {
"Sample GOST R 34.10-2012 (256 bits) Public Key 2 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #2 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR privateKeyLabelGost2012_256_2[] = {
    "Sample GOST R 34.10-2012 (256 bits) Private Key 2 (Aktiv Co.)"
};

/* DEMO ID пары ключей #2 ГОСТ Р 34.10-2012(256) */
static CK_BYTE keyPairIdGost2012_256_2[] = {
"GOST R 34.10-2012 (256 bits) sample key pair 2 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #1 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR publicKeyLabelGost2012_512_1[] = {
"Sample GOST R 34.10-2012 (512 bits) Public Key 1 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #1 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR privateKeyLabelGost2012_512_1[] = {
    "Sample GOST R 34.10-2012 (512 bits) Private Key 1 (Aktiv Co.)"
};

/* DEMO ID пары ключей #1 ГОСТ Р 34.10-2012(512) */
static CK_BYTE keyPairIdGost2012_512_1[] = {
"GOST R 34.10-2012 (512 bits) sample key pair 1 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #2 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR publicKeyLabelGost2012_512_2[] = {
"Sample GOST R 34.10-2012 (512 bits) Public Key 2 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #2 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR privateKeyLabelGost2012_512_2[] = {
    "Sample GOST R 34.10-2012 (512 bits) Private Key 2 (Aktiv Co.)"
};

/* DEMO ID пары ключей #2 ГОСТ Р 34.10-2012(512) */
static CK_BYTE keyPairIdGost2012_512_2[] = {
"GOST R 34.10-2012 (512 bits) sample key pair 2 ID (Aktiv Co.)"
};

/* DEMO-метка симметричного ключа ГОСТ 28147-89 */
static CK_UTF8CHAR secretKeyLabel[] = { "Sample GOST 28147-89 Secret Key (Aktiv Co.)" };

/* DEMO-метка симметричного ключа ГОСТ 34.12-2018 с длиной блока 128 бит (Кузнечик) */
static CK_UTF8CHAR secretKeyKuznechikLabel[] = { "Sample Kuznechik Secret Key (Aktiv Co.)" };

/* DEMO-метка симметричного ключа ГОСТ 34.12-2018 с длиной блока 64 бита (Магма) */
static CK_UTF8CHAR secretKeyMagmaLabel[] = { "Sample Magma Secret Key (Aktiv Co.)" };

/* DEMO ID симметричного ключа ГОСТ 28147-89 */
static CK_BYTE secretKeyId[] = { "GOST 28147-89 Secret Key ID (Aktiv Co.)" };

/* DEMO ID симметричного ключа ГОСТ 34.12-2018 с длиной блока 128 бит (Кузнечик) */
static CK_BYTE secretKeyKuznechikId[] = { "Kuznechik Secret Key ID (Aktiv Co.)" };

/* DEMO ID симметричного ключа ГОСТ 34.12-2018 с длиной блока 64 бита (Магма) */
static CK_BYTE secretKeyMagmaId[] = { "Magma Secret Key ID (Aktiv Co.)" };

/* DEMO-метка выработанного ключа обмена ГОСТ 28147-89 */
static CK_UTF8CHAR derivedKeyLabel[] = { "Derived GOST 28147-89 key" };

/* DEMO-метка выработанного ключа обмена */
static CK_UTF8CHAR genericSecretKeyLabel[] = { "Derived generic secret key" };

/* DEMO-метка для сессионного ключа */
static CK_UTF8CHAR sessionKeyLabel[] = { "GOST 28147-89 key to wrap" };

/* DEMO-метка для демаскированного ключа */
static CK_UTF8CHAR unwrappedKeyLabel[] = { "Unwrapped GOST 28147-89 key" };

/* DEMO-метка для объекта с бинарными данными */
static CK_UTF8CHAR dataObjectLabel[] = "Sample data object label (Aktiv Co.)";

/* DEMO-метка приложения для объекта с бинарными данными */
static CK_UTF8CHAR applicationLabel[] = "Sample application label (Aktiv Co.)";

/************************************************************************
 * Описание меток токена                                                *
 ************************************************************************/
/* DEMO метка Rutoken ("длинная") */
static CK_CHAR tokenLongLabel[] = { "!!!Sample Rutoken Long-long-long-long-long label!!!" };

/* DEMO метка Rutoken ("обычная") */
static CK_CHAR tokenStdLabel[] = { "!!!Sample Rutoken label!!!" };

/* DEMO метка Rutoken */
static CK_UTF8CHAR tokenLabel[] = {
'M', 'y', ' ', 'R', 'u', 't', 'o', 'k', 'e', 'n', ' ', ' ', ' ', ' ', ' ', ' ',
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
};

/*************************************************************************
 * Механизмы PKCS#11                                                     *
 *************************************************************************/
/* Механизм генерации ключевой пары RSA */
static CK_MECHANISM rsaKeyPairGenMech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм шифрования/расшифрования по алгоритму RSA */
static CK_MECHANISM rsaEncDecMech = { CKM_RSA_PKCS, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму RSA */
static CK_MECHANISM rsaSigVerMech = { CKM_RSA_PKCS, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму RSA со встроенным хешированием по алгоритму SHA-256 */
static CK_MECHANISM rsaSigVerMech_WithSha256 = { CKM_SHA256_RSA_PKCS, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ECDSA */
static CK_MECHANISM ecdsaKeyPairGenMech = { CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ECDSA */
static CK_MECHANISM ecdsaSigVerMech = { CKM_ECDSA, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ГОСТ Р 34.10-2001 */
static CK_MECHANISM gostR3410_2001KeyPairGenMech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ГОСТ Р 34.10-2012(256) */
static CK_MECHANISM gostR3410_2012_256KeyPairGenMech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ГОСТ Р 34.10-2012(512) */
static CK_MECHANISM gostR3410_2012_512KeyPairGenMech = { CKM_GOSTR3410_512_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */
static CK_MECHANISM gostR3410_2001SigVerMech = { CKM_GOSTR3410, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(256) */
static CK_MECHANISM gostR3410_2012_256SigVerMech = { CKM_GOSTR3410, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(512) */
static CK_MECHANISM gostR3410_2012_512SigVerMech = { CKM_GOSTR3410_512, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 со встроенным
 * хешированием по алгоритму ГОСТ Р 34.11-94 */
static CK_MECHANISM gostR3410_2001SigVerMech_WithHash = { CKM_GOSTR3410_WITH_GOSTR3411, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(256) со встроенным
 * хешированием по алгоритму ГОСТ Р 34.11-2012(256) */
static CK_MECHANISM gostR3410_2012_256SigVerMech_WithHash = {
CKM_GOSTR3410_WITH_GOSTR3411_12_256, NULL_PTR, 0
};

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(512) со встроенным
 * хешированием по алгоритму ГОСТ Р 34.11-2012(512) */
static CK_MECHANISM gostR3410_2012_512SigVerMech_WithHash = {
CKM_GOSTR3410_WITH_GOSTR3411_12_512, NULL_PTR, 0
};

/* Механизмы генерации симметричного ключа по алгоритму ГОСТ 34.12 */
static CK_MECHANISM kuznechikKeyGenMech = { CKM_KUZNECHIK_KEY_GEN, NULL_PTR, 0 };
static CK_MECHANISM magmaKeyGenMech = { CKM_MAGMA_KEY_GEN, NULL_PTR, 0 };

/* Механизмы шифрования/расшифрования по алгоритму ГОСТ 34.12 */
static CK_MECHANISM kuznechikEncDecEcbMech = { CKM_KUZNECHIK_ECB, NULL_PTR, 0 };
static CK_BYTE kuznechikEncMechParams[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static CK_MECHANISM kuznechikEncDecMech = { CKM_KUZNECHIK_CTR_ACPKM, &kuznechikEncMechParams,
                                            sizeof(kuznechikEncMechParams) };
static CK_MECHANISM magmaEncDecEcbMech = { CKM_MAGMA_ECB, NULL_PTR, 0 };
static CK_BYTE magmaEncMechParams[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static CK_MECHANISM magmaEncDecMech = {
CKM_MAGMA_CTR_ACPKM, &magmaEncMechParams, sizeof(magmaEncMechParams)
};

/* Механизм выработки имитовставки ГОСТ 34.12 */
static CK_MECHANISM kuznechikMacMech = { CKM_KUZNECHIK_MAC, NULL_PTR, 0 };
static CK_MECHANISM magmaMacMech = { CKM_MAGMA_MAC, NULL_PTR, 0 };

/* Механизм генерации симметричного ключа по алгоритму ГОСТ 28147-89 */
static CK_MECHANISM gost28147KeyGenMech = { CKM_GOST28147_KEY_GEN, NULL_PTR, 0 };

/* Механизм шифрования/расшифрования по алгоритму ГОСТ 28147-89 */
static CK_MECHANISM gost28147EncDecEcbMech = { CKM_GOST28147_ECB, NULL_PTR, 0 };
static CK_MECHANISM gost28147EncDecMech = { CKM_GOST28147, NULL_PTR, 0 };

/* Механизм выработки имитовставки ГОСТ 28147-89 */
static CK_MECHANISM gost28147MacMech = { CKM_GOST28147_MAC, NULL_PTR, 0 };

/* Механизм выработки HMAC по алгоритму ГОСТ Р 34.11-94 */
static CK_MECHANISM gostR3411HmacMech = { CKM_GOSTR3411_HMAC, NULL_PTR, 0 };

/* Механизм выработки HMAC по алгоритму ГОСТ Р 34.11-2012(256) */
static CK_MECHANISM gostR3411_2012_256HmacMech = { CKM_GOSTR3411_12_256_HMAC, NULL_PTR, 0 };

/* Механизм выработки HMAC по алгоритму ГОСТ Р 34.11-2012(512) */
static CK_MECHANISM gostR3411_2012_512HmacMech = { CKM_GOSTR3411_12_512_HMAC, NULL_PTR, 0 };

/* Механизм хеширования SHA-256 */
static CK_MECHANISM sha256Mech = { CKM_SHA256, NULL_PTR, 0 };

/* Механизм хеширования ГОСТ Р 34.11-94 */
static CK_MECHANISM gostR3411_1994HashMech = { CKM_GOSTR3411, NULL_PTR, 0 };

/* Механизм хеширования ГОСТ Р 34.11-2012(256) */
static CK_MECHANISM gostR3411_2012_256HashMech = { CKM_GOSTR3411_12_256, NULL_PTR, 0 };

/* Механизм хеширования ГОСТ Р 34.11-2012(512) */
static CK_MECHANISM gostR3411_2012_512HashMech = { CKM_GOSTR3411_12_512, NULL_PTR, 0 };

/* Механизм для маскирования/демаскирования ключа */
static CK_MECHANISM gost28147WrapMech = { CKM_GOST28147_KEY_WRAP, NULL_PTR, 0 };

/* Механизм выработки ключа обмена по алгоритму VKO GOST R 34.10-2001 */
static CK_MECHANISM gostR3410_2001DerivationMech = { CKM_GOSTR3410_DERIVE, NULL_PTR, 0 };

/* Механизм выработки ключа обмена по алгоритму VKO GOST R 34.10-2012 */
static CK_MECHANISM gostR3410_12DerivationMech = { CKM_GOSTR3410_12_DERIVE, NULL_PTR, 0 };

/* Механизм выработки ключа обмена по алгоритму KEG для TLS 1.2 */
static CK_MECHANISM gostKegDerivationMech = { CKM_GOST_KEG, NULL_PTR, 0 };

/* Параметры для выработки ключа обмена */
static CK_GOSTR3410_DERIVE_PARAMS deriveParameters = { CKD_CPDIVERSIFY_KDF, NULL_PTR, 0, NULL_PTR, 0 };

/**************************************************************************
 * Механизмы PKCS#11 с программной реализацией.                           *
 * Использование данных механизмов предполагает выполнение                *
 * криптографической операции на центральном процессоре, что может        *
 * положительно повлиять на скорость выполнения операции, но отрицательно *
 * на обеспечение безопасности                                            *
 **************************************************************************/
/* Механизм программного хеширования ГОСТ Р 34.11-94
   static CK_MECHANISM gostR3411_1994HashMech = { CKM_GOSTR3411, parametersGostR3411_1994,
   sizeof(parametersGostR3411_1994) }; */

/* Механизм программного хеширования ГОСТ Р 34.11-2012(256)
   static CK_MECHANISM gostR3411_2012_256HashMech = { CKM_GOSTR3411_12_256, parametersGostR3411_2012_256,
   sizeof(parametersGostR3411_2012_256) }; */

/* Механизм программного хеширования ГОСТ Р 34.11-2012(512)
   static CK_MECHANISM gostR3411_2012_512HashMech = { CKM_GOSTR3411_12_512, parametersGostR3411_2012_512,
   sizeof(parametersGostR3411_2012_512) }; */

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 со встроенным
   программным хешированием по алгоритму ГОСТ Р 34.11-94
   static CK_MECHANISM gostR3410_2001SigVerMech_WithHash = { CKM_GOSTR3410_WITH_GOSTR3411,
        parametersGostR3411_1994, sizeof(parametersGostR3411_1994) }; */

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(256) со встроенным
   программным хешированием по алгоритму ГОСТ Р 34.11-2012(256)
   static CK_MECHANISM gostR3410_2012_256SigVerMech_WithHash = {
        CKM_GOSTR3410_WITH_GOSTR3411_12_256, parametersGostR3411_2012_256,
sizeof(parametersGostR3411_2012_256)
}; */

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(512) со встроенным
   программным хешированием по алгоритму ГОСТ Р 34.11-2012(512)
   static CK_MECHANISM gostR3410_2012_512SigVerMech_WithHash = {
        CKM_GOSTR3410_WITH_GOSTR3411_12_512, parametersGostR3411_2012_512,
sizeof(parametersGostR3411_2012_512) };
*/

/*************************************************************************
 * Запрос на получение сертификата                                       *
 *************************************************************************/
/*************************************************************************
 * Список полей DN (Distinguished Name)                                  *
 *************************************************************************/
CK_CHAR_PTR dn[] = {
    (CK_CHAR_PTR) "CN",                // Тип поля CN (Common Name)
    (CK_CHAR_PTR) "UTF8String:Иванов", // Значение
    (CK_CHAR_PTR) "C",                 // C (Country)
    (CK_CHAR_PTR) "RU",
    (CK_CHAR_PTR) "2.5.4.5", // SN (Serial Number)
    (CK_CHAR_PTR) "12312312312",
    (CK_CHAR_PTR) "1.2.840.113549.1.9.1", // E (E-mail)
    (CK_CHAR_PTR) "ivanov@mail.ru",
    (CK_CHAR_PTR) "ST", // ST (State or province)
    (CK_CHAR_PTR) "UTF8String:Москва",
    (CK_CHAR_PTR) "O", // O (Organization)
    (CK_CHAR_PTR) "CompanyName",
    (CK_CHAR_PTR) "OU", // OU (Organizational Unit)
    (CK_CHAR_PTR) "Devel",
    (CK_CHAR_PTR) "L", // L (Locality)
    (CK_CHAR_PTR) "Moscow",
};

/*************************************************************************
 * Список дополнительных полей                                           *
 *************************************************************************/
CK_CHAR_PTR exts[] = {
    (CK_CHAR_PTR) "keyUsage", // Использование ключа
    (CK_CHAR_PTR) "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment",
    (CK_CHAR_PTR) "extendedKeyUsage", // Дополнительное использование
    (CK_CHAR_PTR) "1.2.643.2.2.34.6,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.4",
    (CK_CHAR_PTR) "2.5.29.14", // Идентификатор ключа субъекта (SKI)
    (CK_CHAR_PTR) "hash", // Если задать значение hash - идентификатор ключа субъекта будет
                  // сформирован библиотекой автоматически.
// Также идентификатор ключа субъекта можно задать вручную
                  // (CK_CHAR_PTR)"ASN1:FORMAT:HEX,OCTETSTRING:FE117B93CEC6B5065E1613E155D3A9CA597C0F81",
    (CK_CHAR_PTR) "2.5.29.17", // Дополнительное имя (пример с кодированием в виде DER)
    (CK_CHAR_PTR) "DER:30:0F:81:0D:65:78:61:6d:70:6c:65:40:79:61:2E:72:75",
    (CK_CHAR_PTR) "2.5.29.32", // Политики сертификата (кодирование в виде DER с пометкой "critical")
    (CK_CHAR_PTR) "critical,DER:30:0A:30:08:06:06:2A:85:03:64:71:01",
    (CK_CHAR_PTR) "1.2.643.100.111", // Средства электронной подписи владельца
    (CK_CHAR_PTR) "ASN1:UTF8String:СКЗИ \\\"Рутокен ЭЦП 2.0\\\"",
};

/*************************************************************************
 * Функция преобразования ошибки PKCS#11 к строке                        *
 *************************************************************************/
static const char* rvToStr(CK_RV rv) {
    switch (rv) {
    case CKR_OK:
        return "CKR_OK";
    case CKR_CANCEL:
        return "CKR_CANCEL";
    case CKR_HOST_MEMORY:
        return "CKR_HOST_MEMORY";
    case CKR_SLOT_ID_INVALID:
        return "CKR_SLOT_ID_INVALID";
    case CKR_GENERAL_ERROR:
        return "CKR_GENERAL_ERROR";
    case CKR_FUNCTION_FAILED:
        return "CKR_FUNCTION_FAILED";
    case CKR_ARGUMENTS_BAD:
        return "CKR_ARGUMENTS_BAD";
    case CKR_NO_EVENT:
        return "CKR_NO_EVENT";
    case CKR_NEED_TO_CREATE_THREADS:
        return "CKR_NEED_TO_CREATE_THREADS";
    case CKR_CANT_LOCK:
        return "CKR_CANT_LOCK";
    case CKR_ATTRIBUTE_READ_ONLY:
        return "CKR_ATTRIBUTE_READ_ONLY";
    case CKR_ATTRIBUTE_SENSITIVE:
        return "CKR_ATTRIBUTE_SENSITIVE";
    case CKR_ATTRIBUTE_TYPE_INVALID:
        return "CKR_ATTRIBUTE_TYPE_INVALID";
    case CKR_ATTRIBUTE_VALUE_INVALID:
        return "CKR_ATTRIBUTE_VALUE_INVALID";
    case CKR_DATA_INVALID:
        return "CKR_DATA_INVALID";
    case CKR_DATA_LEN_RANGE:
        return "CKR_DATA_LEN_RANGE";
    case CKR_DEVICE_ERROR:
        return "CKR_DEVICE_ERROR";
    case CKR_DEVICE_MEMORY:
        return "CKR_DEVICE_MEMORY";
    case CKR_DEVICE_REMOVED:
        return "CKR_DEVICE_REMOVED";
    case CKR_ENCRYPTED_DATA_INVALID:
        return "CKR_ENCRYPTED_DATA_INVALID";
    case CKR_ENCRYPTED_DATA_LEN_RANGE:
        return "CKR_ENCRYPTED_DATA_LEN_RANGE";
    case CKR_FUNCTION_CANCELED:
        return "CKR_FUNCTION_CANCELED";
    case CKR_FUNCTION_NOT_PARALLEL:
        return "CKR_FUNCTION_NOT_PARALLEL";
    case CKR_FUNCTION_NOT_SUPPORTED:
        return "CKR_FUNCTION_NOT_SUPPORTED";
    case CKR_KEY_HANDLE_INVALID:
        return "CKR_KEY_HANDLE_INVALID";
    case CKR_KEY_SIZE_RANGE:
        return "CKR_KEY_SIZE_RANGE";
    case CKR_KEY_TYPE_INCONSISTENT:
        return "CKR_KEY_TYPE_INCONSISTENT";
    case CKR_KEY_NOT_NEEDED:
        return "CKR_KEY_NOT_NEEDED";
    case CKR_KEY_CHANGED:
        return "CKR_KEY_CHANGED";
    case CKR_KEY_NEEDED:
        return "CKR_KEY_NEEDED";
    case CKR_KEY_INDIGESTIBLE:
        return "CKR_KEY_INDIGESTIBLE";
    case CKR_KEY_FUNCTION_NOT_PERMITTED:
        return "CKR_KEY_FUNCTION_NOT_PERMITTED";
    case CKR_KEY_NOT_WRAPPABLE:
        return "CKR_KEY_NOT_WRAPPABLE";
    case CKR_KEY_UNEXTRACTABLE:
        return "CKR_KEY_UNEXTRACTABLE";
    case CKR_MECHANISM_INVALID:
        return "CKR_MECHANISM_INVALID";
    case CKR_MECHANISM_PARAM_INVALID:
        return "CKR_MECHANISM_PARAM_INVALID";
    case CKR_OBJECT_HANDLE_INVALID:
        return "CKR_OBJECT_HANDLE_INVALID";
    case CKR_OPERATION_ACTIVE:
        return "CKR_OPERATION_ACTIVE";
    case CKR_OPERATION_NOT_INITIALIZED:
        return "CKR_OPERATION_NOT_INITIALIZED";
    case CKR_PIN_INCORRECT:
        return "CKR_PIN_INCORRECT";
    case CKR_PIN_INVALID:
        return "CKR_PIN_INVALID";
    case CKR_PIN_LEN_RANGE:
        return "CKR_PIN_LEN_RANGE";
    case CKR_PIN_EXPIRED:
        return "CKR_PIN_EXPIRED";
    case CKR_PIN_LOCKED:
        return "CKR_PIN_LOCKED";
    case CKR_SESSION_CLOSED:
        return "CKR_SESSION_CLOSED";
    case CKR_SESSION_COUNT:
        return "CKR_SESSION_COUNT";
    case CKR_SESSION_HANDLE_INVALID:
        return "CKR_SESSION_HANDLE_INVALID";
    case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
        return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
    case CKR_SESSION_READ_ONLY:
        return "CKR_SESSION_READ_ONLY";
    case CKR_SESSION_EXISTS:
        return "CKR_SESSION_EXISTS";
    case CKR_SESSION_READ_ONLY_EXISTS:
        return "CKR_SESSION_READ_ONLY_EXISTS";
    case CKR_SESSION_READ_WRITE_SO_EXISTS:
        return "CKR_SESSION_READ_WRITE_SO_EXISTS";
    case CKR_SIGNATURE_INVALID:
        return "CKR_SIGNATURE_INVALID";
    case CKR_SIGNATURE_LEN_RANGE:
        return "CKR_SIGNATURE_LEN_RANGE";
    case CKR_TEMPLATE_INCOMPLETE:
        return "CKR_TEMPLATE_INCOMPLETE";
    case CKR_TEMPLATE_INCONSISTENT:
        return "CKR_TEMPLATE_INCONSISTENT";
    case CKR_TOKEN_NOT_PRESENT:
        return "CKR_TOKEN_NOT_PRESENT";
    case CKR_TOKEN_NOT_RECOGNIZED:
        return "CKR_TOKEN_NOT_RECOGNIZED";
    case CKR_TOKEN_WRITE_PROTECTED:
        return "CKR_TOKEN_WRITE_PROTECTED";
    case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
        return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
    case CKR_UNWRAPPING_KEY_SIZE_RANGE:
        return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
    case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
        return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
    case CKR_USER_ALREADY_LOGGED_IN:
        return "CKR_USER_ALREADY_LOGGED_IN";
    case CKR_USER_NOT_LOGGED_IN:
        return "CKR_USER_NOT_LOGGED_IN";
    case CKR_USER_PIN_NOT_INITIALIZED:
        return "CKR_USER_PIN_NOT_INITIALIZED";
    case CKR_USER_TYPE_INVALID:
        return "CKR_USER_TYPE_INVALID";
    case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
        return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
    case CKR_USER_TOO_MANY_TYPES:
        return "CKR_USER_TOO_MANY_TYPES";
    case CKR_WRAPPED_KEY_INVALID:
        return "CKR_WRAPPED_KEY_INVALID";
    case CKR_WRAPPED_KEY_LEN_RANGE:
        return "CKR_WRAPPED_KEY_LEN_RANGE";
    case CKR_WRAPPING_KEY_HANDLE_INVALID:
        return "CKR_WRAPPING_KEY_HANDLE_INVALID";
    case CKR_WRAPPING_KEY_SIZE_RANGE:
        return "CKR_WRAPPING_KEY_SIZE_RANGE";
    case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
        return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
    case CKR_RANDOM_SEED_NOT_SUPPORTED:
        return "CKR_RANDOM_SEED_NOT_SUPPORTED";
    case CKR_RANDOM_NO_RNG:
        return "CKR_RANDOM_NO_RNG";
    case CKR_DOMAIN_PARAMS_INVALID:
        return "CKR_DOMAIN_PARAMS_INVALID";
    case CKR_BUFFER_TOO_SMALL:
        return "CKR_BUFFER_TOO_SMALL";
    case CKR_SAVED_STATE_INVALID:
        return "CKR_SAVED_STATE_INVALID";
    case CKR_INFORMATION_SENSITIVE:
        return "CKR_INFORMATION_SENSITIVE";
    case CKR_STATE_UNSAVEABLE:
        return "CKR_STATE_UNSAVEABLE";
    case CKR_CRYPTOKI_NOT_INITIALIZED:
        return "CKR_CRYPTOKI_NOT_INITIALIZED";
    case CKR_CRYPTOKI_ALREADY_INITIALIZED:
        return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
    case CKR_MUTEX_BAD:
        return "CKR_MUTEX_BAD";
    case CKR_MUTEX_NOT_LOCKED:
        return "CKR_MUTEX_NOT_LOCKED";
    case CKR_NEW_PIN_MODE:
        return "CKR_NEW_PIN_MODE";
    case CKR_NEXT_OTP:
        return "CKR_NEXT_OTP";
    case CKR_FUNCTION_REJECTED:
        return "CKR_FUNCTION_REJECTED";
    case CKR_CORRUPTED_MAPFILE:
        return "CKR_CORRUPTED_MAPFILE";
    case CKR_WRONG_VERSION_FIELD:
        return "CKR_WRONG_VERSION_FIELD";
    case CKR_WRONG_PKCS1_ENCODING:
        return "CKR_WRONG_PKCS1_ENCODING";
    case CKR_RTPKCS11_DATA_CORRUPTED:
        return "CKR_RTPKCS11_DATA_CORRUPTED";
    case CKR_RTPKCS11_RSF_DATA_CORRUPTED:
        return "CKR_RTPKCS11_RSF_DATA_CORRUPTED";
    case CKR_SM_PASSWORD_INVALID:
        return "CKR_SM_PASSWORD_INVALID";
    case CKR_LICENSE_READ_ONLY:
        return "CKR_LICENSE_READ_ONLY";
    default:
        return "Unknown error";
    }
}

/*************************************************************************
 * Макросы проверки ошибки. Если произошла ошибка, то выводится          *
 * сообщение и осуществляется переход на заданную метку                  *
 *************************************************************************/
#define CHECK_AND_LOG_ONLY_ERROR(expression, errMsg, label) \
    do {                                                    \
        if (!(expression)) {                                \
            printf(" -> Failed\n%s\n", errMsg);             \
            goto label;                                     \
        }                                                   \
    } while (0)

#define CHECK_AND_LOG(msg, expression, errMsg, label) \
    do {                                              \
        printf("%s", msg);                            \
        if (!(expression)) {                          \
            printf(" -> Failed\n%s\n", errMsg);       \
            goto label;                               \
        } else {                                      \
            printf(" -> OK\n");                       \
        }                                             \
    } while (0)

#define CHECK(msg, expression, label) CHECK_AND_LOG(msg, expression, "", label)

/*************************************************************************
 * Макросы проверки ошибки при освобождении ресурсов.                    *
 * Если произошла ошибка, то выводится сообщение                         *
 * и выставляется значение переменной errorCode                          *
 *************************************************************************/
#define CHECK_RELEASE_AND_LOG(msg, expression, errMsg, errorCode) \
    do {                                                          \
        printf("%s", msg);                                        \
        if (!(expression)) {                                      \
            printf(" -> Failed\n%s\n", errMsg);                   \
            errorCode = 1;                                        \
        } else {                                                  \
            printf(" -> OK\n");                                   \
        }                                                         \
    } while (0)

#define CHECK_RELEASE(msg, expression, errorCode) CHECK_RELEASE_AND_LOG(msg, expression, "", errorCode)

/*************************************************************************
 * Макросы проверки ошибки. Если произошла ошибка, то выводится          *
 * сообщение и выполняется оператор проверочного утверждения             *
 *************************************************************************/
#define ASSERT_AND_LOG_AND_ERRMSG(msg, expression, errMsg) \
    do {                                                   \
        printf("%s", msg);                                 \
        if (!(expression)) {                               \
            printf("%s -> Failed\n%s\n", msg, errMsg);     \
            abort();                                       \
        } else {                                           \
            printf(" -> OK\n");                            \
        }                                                  \
    } while (0)

#define ASSERT_AND_LOG(msg, expression) ASSERT_AND_LOG_AND_ERRMSG(msg, expression, "")

#define ASSERT(msg, expression)            \
    do {                                   \
        if (!(expression)) {               \
            printf("%s -> Failed\n", msg); \
            abort();                       \
        }                                  \
    } while (0)

/*************************************************************************
 * Функция поиска объектов по заданному шаблону                          *
 *************************************************************************/
static int findObjects(CK_FUNCTION_LIST_PTR functionList, // Указатель на список функций PKCS#11
                       CK_SESSION_HANDLE session,         // Дескриптор открытой сессии
                       CK_ATTRIBUTE_PTR attributes,       // Массив с шаблоном для поиска
                       CK_ULONG attrCount,                // Количество атрибутов в массиве поиска
                       CK_OBJECT_HANDLE_PTR* objects,     // Массив для записи найденных объектов
                       CK_ULONG* objectsCount             // Количество найденных объектов
) {
    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    CK_ULONG newObjectsCount;    // Количество объектов, найденных при конкретном вызове C_FindObjects
    CK_ULONG bufferSize;         // Текущий размер буфера с объектами
    CK_OBJECT_HANDLE_PTR buffer; // Буфер, получаемый из realloc
    int errorCode = 1;           // Флаг ошибки

    /*************************************************************************
     * Инициализировать операцию поиска                                      *
     *************************************************************************/
    rv = functionList->C_FindObjectsInit(session, attributes, attrCount);
    CHECK_AND_LOG("  C_FindObjectsInit", rv == CKR_OK, rvToStr(rv), exit);

    /*************************************************************************
     * Найти все объекты, соответствующие критериям поиска                   *
     *************************************************************************/
    *objects = NULL;
    *objectsCount = 0;

    for (bufferSize = 8;; bufferSize *= 2) {
        buffer = (CK_OBJECT_HANDLE_PTR)realloc(*objects, bufferSize * sizeof(CK_OBJECT_HANDLE));
        CHECK("  Memory allocation for object handles", buffer != NULL, find_final);
        *objects = buffer;

        rv = functionList->C_FindObjects(session, *objects + *objectsCount, bufferSize - *objectsCount,
                                         &newObjectsCount);
        CHECK_AND_LOG("  C_FindObjects", rv == CKR_OK, rvToStr(rv), find_final);

        *objectsCount += newObjectsCount;

        if (*objectsCount < bufferSize) {
            break;
        }
    }

    /*************************************************************************
     * Освободить неиспользуемую память                                      *
     *************************************************************************/
    if (*objectsCount != 0) {
        buffer = (CK_OBJECT_HANDLE_PTR)realloc(*objects, *objectsCount * sizeof(CK_OBJECT_HANDLE));
        CHECK("  Memory reallocation for object handles", buffer != NULL, find_final);
        *objects = buffer;
    }

    errorCode = 0;

    /*************************************************************************
     * Деинициализировать операцию поиска                                    *
     *************************************************************************/
find_final:
    rv = functionList->C_FindObjectsFinal(session);
    CHECK_RELEASE_AND_LOG("  C_FindObjectsFinal", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под объекты                               *
     *************************************************************************/
    if (errorCode || *objectsCount == 0) {
        free(*objects);
        *objects = NULL_PTR;
    }

exit:
    return errorCode;
}

/*************************************************************************
 * Функция вывода шестнадцатеричного буфера заданной длины               *
 *************************************************************************/
static void printHexBuffer(const CK_BYTE* buffer,        // Буфер
                           const CK_ULONG length,        // Длина буфера
                           const CK_ULONG width,         // Байт в строке
                           const CK_BYTE offset,         // Смещение каждой строки
                           const CK_BYTE firstLineOffset // Смещение первой строки
) {
    unsigned int lineOffset = firstLineOffset;
    for (unsigned int i = 0; i < length; ++i) {
        if (width != 0) {
            if (i % width == 0) {
                for (unsigned int j = 0; j < lineOffset; ++j) {
                    printf(" ");
                }
            }
        }

        printf("%02X ", buffer[i]);

        if (width != 0) {
            if ((i + 1) % width == 0 || (i + 1) == length) {
                printf("\n");
            }
        } else if ((i + 1) == length) {
            printf("\n");
        }
        lineOffset = offset;
    }
}

/*************************************************************************
 * Функция вывода шестнадцатеричного буфера по 16 байт в строке          *
 *************************************************************************/
static void printHex(const CK_BYTE* buffer, // Буфер
                     const CK_ULONG length  // Длина буфера
) {
    printHexBuffer(buffer, length, 16, 3, 3);
}

/*************************************************************************
 * Функция вывода UTF-8. Выводит символы 0-127 и кириллицу. Возвращает 0 *
 * в случае успешного выполнения, иначе не 0                             *
 *************************************************************************/
static int printUTF8String(CK_BYTE* info) {
#ifdef _WIN32
    CK_ULONG sym = 0;
    UINT cp = GetConsoleOutputCP();
    BOOL set = SetConsoleOutputCP(866); // Кодировка cp-866
    if (set == FALSE) {
        return 1;
    }
    while (*info) {
        if (*info < 0x80) {
            printf("%c", *info); // Вывод однобайтовых символов
            ++info;
        } else if (*info & 0xC0) { // Вывод двухбайтовых символов
            sym = ((*info & 0x1F) << 6) + (*(info + 1) & 0x3F);
            if (sym >= 0x0410 && sym <= 0x042F) { // Прописные
                printf("%c", sym - 0x0410 + 0x80);
            } else if (sym >= 0x0430 && sym <= 0x043F) { // Строчные до 'р'
                printf("%c", sym - 0x0430 + 0xA0);
            } else if (sym >= 0x0440 && sym <= 0x044F) { // Строчные после 'р'
                printf("%c", sym - 0x0440 + 0xE0);
            } else if (sym == 0x0401) { // Ё
                printf("%c", 0xF0);
            } else if (sym == 0x0451) { // ё
                printf("%c", 0xF1);
            } else {
                printf("?"); // Все остальные двухбайтные символы
            }
            info += 2;
        } else if (*info & 0xE0) { // 3 и более байтные символы
            info += 3;
            printf("?");
        } else if (*info & 0xF0) {
            info += 4;
            printf("?");
        } else if (*info & 0xF8) {
            info += 5;
            printf("?");
        } else if (*info & 0xFC) {
            info += 6;
            printf("?");
        } else {
            ++info;
        }
    }
    set = SetConsoleOutputCP(cp);
    return !set;
#else
    printf("%s", info);
    return 0;
#endif
}

/*************************************************************************
 * Функция конвертирования 6-битного кода в печатный символ Base64       *
 *************************************************************************/
static char ConvertCodeToSymBase64(CK_BYTE code // 6-битный код
) {
    const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    if (code < 0x40) {
        return alphabet[(int)code];
    } else {
        return '?';
    }
}

/*************************************************************************
 * Функция выборки 6 бит из массива байт                                 *
 *************************************************************************/
static CK_BYTE GetNext6Bit(
CK_BYTE_PTR csr, // Указатель на начало массива
    CK_ULONG start, // Номер бита в массиве, с которого начинается группа из 6 бит
    CK_ULONG end // Номер последнего бита массива
) {
    CK_BYTE diff = start % 8;
    csr += start / 8;
    if (end - start > 8) {
        return 0x3F & (*csr << diff | *(csr + 1) >> (8 - diff)) >> 2;
    } else {
        return 0x3F & (*csr << diff >> 2);
    }
}

/*************************************************************************
 * Функция конвертирования массива байт в строку Base64                  *
 *************************************************************************/
static void ConvertToBase64String(
CK_BYTE_PTR data, // Исходные данные
    CK_ULONG size,    // Длина исходного массива
    char** result // Результирующие данные (нуль-терминированная строка)
) {
    CK_ULONG i = 0;
    char* pt;
    *result = (char*)calloc(((size_t)size + 2) / 3 * 4 + 1, sizeof(char));
    if (*result != NULL) {
        memset(*result, '=', ((size_t)size + 2) / 3 * 4);
        for (pt = *result; i < size * 8; i += 6, ++pt) {
            *pt = ConvertCodeToSymBase64(GetNext6Bit(data, i, size * 8));
        }
    }
}

/*************************************************************************
 * Функция преобразования массива байт в PEM формат                      *
 *************************************************************************/
static void GetBytesAsPem(CK_BYTE_PTR source, // Исходные данные
                          CK_ULONG size,      // Длина исходного массива
                          const char* header, // Начальный тег
                          const char* footer, // Конечный тег
                          char** result       // Результирующий запрос
) {
    size_t length;
    size_t width = 0x40;
    char* buffer;
    size_t i;

    ConvertToBase64String(source, size, &buffer);
    if (buffer == NULL) {
        *result = NULL;
        return;
    }
    length = strlen(buffer);
    *result = (char*)calloc(strlen(header)                 // Место под начальный тег
                                + length                   // Место под base64 строку
                                + strlen(footer)           // Место под конечный тег
                                + (length - 1) / width + 1 // Место под переносы строки
                                + 1,                       // Нуль-байт
                            sizeof(char));
    if (*result == NULL) {
        free(buffer);
        return;
    }
    // компоновка данных
    strcat(*result, header);
    for (i = 0; i < length; i += width) {
        strncat(*result, buffer + i, width);
        strcat(*result, "\n");
    }
    strcat(*result, footer);

    free(buffer);
}

/*************************************************************************
 * Функция получения CSR в формате PEM                                   *
 *************************************************************************/
static void GetCSRAsPEM(CK_BYTE_PTR source, // Исходные данные
                        CK_ULONG size,      // Длина исходного массива
                        char** result       // Результирующий запрос
) {
    const char* begin = "-----BEGIN NEW CERTIFICATE REQUEST-----\n"; // Начало запроса
    const char* end = "-----END NEW CERTIFICATE REQUEST-----\n";     // Конец запроса

    GetBytesAsPem(source, size, begin, end, result);
}

/*************************************************************************
 * Функция получения тела сертификата в формате PEM                      *
 *************************************************************************/
static void GetCertAsPem(CK_BYTE_PTR source, // Исходные данные
                         CK_ULONG size,      // Длина исходного массива
                         char** result       // Указатель на строку с результатом
) {
    const char* begin = "-----BEGIN CERTIFICATE-----\n"; // Начало сертификата
    const char* end = "-----END CERTIFICATE-----\n";     // Конец сертификата

    GetBytesAsPem(source, size, begin, end, result);
}

#endif // PKCS11_COMMON_H
Файл BioCommon.h. Описание типа объекта набора отпечатков пальцев 
/************************************************************************
* В каждом примере Bio*.c работа ведется с первым найденным *
* набором отпечатков. *
* Если на токене присутствует более одного набора отпечатков, *
* для работы с нужным набором следует указать *
* CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID в шаблоне поиска *
* объекта набора отпечатков *
 ************************************************************************/

#ifndef BioCommon_H
#define BioCommon_H

#include "Common.h"

/************************************************************************
 * Описание типа объекта набора отпечатков пальцев                      *
 ************************************************************************/
static CK_OBJECT_CLASS authObject = CKO_VENDOR_AUTHENTICATION_FACTOR;
static CK_VENDOR_AUTHENTICATION_FACTOR_TYPE authType = CKVAF_BIO_FP_CONVOLUTION;

/************************************************************************
 * Массив, представляющий из себя отпечаток пальца, заполненный         *
 * по ГОСТ 19794-2-2013                                                 *
 ************************************************************************/
CK_BYTE initFingerprint[] = {
    0x46, 0x4D, 0x52, 0x00, 0x30, 0x33, 0x30, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x01, 0x00,
    0x00, 0x00, 0x00, 0x86, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0xC5, 0x00, 0x01, 0x40, 0x01, 0xE0,
    0x50, 0x14, 0x40, 0x6A, 0x00, 0x48, 0xC6, 0x40, 0x59, 0x00, 0xD2, 0xE1, 0x40, 0xBA, 0x00,
    0x40, 0xA4, 0x00, 0xC4, 0x00, 0x3C, 0xB6, 0x40, 0xB0, 0x00, 0x62, 0x2E, 0x00, 0xA5, 0x00,
    0xA0, 0x72, 0x40, 0xE6, 0x00, 0xB6, 0x1E, 0x00, 0x62, 0x00, 0xB4, 0x5A, 0x00, 0xBD, 0x00,
    0x2E, 0xDA, 0x40, 0xAD, 0x00, 0x96, 0x70, 0x40, 0xCA, 0x00, 0x54, 0xAD, 0x00, 0xE6, 0x00,
    0x4C, 0x3F, 0x40, 0xF8, 0x00, 0x48, 0x36, 0x00, 0x58, 0x00, 0x4E, 0x44, 0x00, 0x7A, 0x00,
    0x42, 0x39, 0x00, 0x96, 0x00, 0x82, 0x52, 0x40, 0x9C, 0x00, 0x66, 0x42, 0x00, 0x80, 0x01,
    0x0E, 0xF6, 0x40, 0xCE, 0x00, 0x2A, 0xD2, 0x00, 0xB7, 0x01, 0x08, 0x86, 0x00, 0x00
};

/************************************************************************
 * Массивы, представляющие из себя отпечатки пальцев, заполненные       *
 * по ГОСТ 19794-2-2013. Используется для замены изначального отпечатка *
 ************************************************************************/
CK_BYTE updateFingerprint1[] = {
    0x46, 0x4D, 0x52, 0x00, 0x30, 0x33, 0x30, 0x00, 0x00, 0x00, 0x01, 0x17, 0x00, 0x01, 0x00,
    0x00, 0x00, 0x01, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0xC5, 0x00, 0x01, 0x40, 0x01, 0xE0,
    0x50, 0x2E, 0x00, 0x68, 0x00, 0xBC, 0x3B, 0x00, 0x78, 0x00, 0xEC, 0x44, 0x00, 0x74, 0x01,
    0x14, 0x52, 0x00, 0xA6, 0x00, 0x90, 0x63, 0x00, 0x9C, 0x01, 0x64, 0x70, 0x40, 0xD2, 0x00,
    0xD0, 0x51, 0x00, 0xEC, 0x00, 0x5C, 0xD8, 0x00, 0xE4, 0x00, 0xE4, 0x3F, 0x00, 0xDA, 0x01,
    0x38, 0x1A, 0x00, 0xE4, 0x01, 0x14, 0x2E, 0x01, 0x1A, 0x00, 0xC8, 0x3F, 0x01, 0x26, 0x00,
    0xB0, 0x3F, 0x00, 0xD2, 0x00, 0x4B, 0xE1, 0x01, 0x0B, 0x01, 0x31, 0x9F, 0x40, 0x8C, 0x00,
    0x72, 0xE9, 0x00, 0xB2, 0x00, 0x56, 0xE1, 0x00, 0xB4, 0x01, 0x32, 0x72, 0x40, 0xCA, 0x00,
    0xF6, 0x44, 0x01, 0x33, 0x00, 0xD4, 0x36, 0x00, 0xE4, 0x01, 0x65, 0x8D, 0x00, 0x83, 0x00,
    0x9A, 0x8B, 0x00, 0x8C, 0x00, 0xA8, 0x9A, 0x00, 0xB8, 0x00, 0x78, 0x63, 0x40, 0xB3, 0x00,
    0xBA, 0x63, 0x00, 0xEC, 0x00, 0x68, 0x5C, 0x00, 0xDF, 0x01, 0x4A, 0x8D, 0x41, 0x10, 0x00,
    0x60, 0xDF, 0x00, 0xE3, 0x01, 0x4A, 0x18, 0x00, 0xF6, 0x00, 0xEC, 0x3B, 0x01, 0x06, 0x01,
    0x0C, 0x32, 0x01, 0x22, 0x01, 0x24, 0x28, 0x00, 0x4F, 0x01, 0x0D, 0xD6, 0x00, 0x79, 0x00,
    0xA1, 0xFB, 0x40, 0x93, 0x00, 0xC5, 0xB1, 0x00, 0x54, 0x00, 0xDE, 0x49, 0x00, 0x52, 0x01,
    0x02, 0xD4, 0x00, 0x7E, 0x00, 0x7A, 0x76, 0x00, 0x77, 0x00, 0xA8, 0xB0, 0x00, 0x80, 0x01,
    0x3E, 0xE9, 0x00, 0xBA, 0x00, 0xFA, 0x48, 0x40, 0xDA, 0x00, 0xC2, 0x51, 0x00, 0xFE, 0x00,
    0x82, 0xCD, 0x41, 0x23, 0x00, 0x78, 0xC9, 0x01, 0x14, 0x01, 0x16, 0x2B, 0x00, 0xAE, 0x01,
    0x05, 0x46, 0x00, 0xD9, 0x01, 0x6F, 0x12, 0x00, 0x00
};

CK_BYTE updateFingerprint2[] = {
    0x46, 0x4D, 0x52, 0x00, 0x30, 0x33, 0x30, 0x00, 0x00, 0x00, 0x01, 0x5D, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0xC5, 0x00, 0x01, 0x40, 0x01, 0xE0,
0x50, 0x3C, 0x00, 0x26, 0x00, 0x58, 0x9F, 0x40, 0x36, 0x01, 0x60, 0xEB, 0x40, 0x5A, 0x01,
0x00, 0x42, 0x00, 0x9C, 0x00, 0x4C, 0x8D, 0x40, 0x9F, 0x01, 0x46, 0x8D, 0x00, 0xB8, 0x00,
0xF4, 0x32, 0x00, 0xC6, 0x01, 0x20, 0x28, 0x01, 0x08, 0x01, 0x34, 0x29, 0x41, 0x1D, 0x00,
0xDA, 0x39, 0x40, 0xD3, 0x00, 0x91, 0xC2, 0x00, 0xFA, 0x00, 0x43, 0xE9, 0x40, 0xFA, 0x00,
0xA3, 0xBF, 0x40, 0x27, 0x00, 0x6C, 0xA4, 0x00, 0x1F, 0x01, 0x2C, 0x56, 0x00, 0x5A, 0x00,
0x2E, 0x88, 0x40, 0x48, 0x00, 0xD2, 0x36, 0x00, 0x72, 0x01, 0x5E, 0x74, 0x40, 0x8E, 0x01,
0x06, 0x25, 0x40, 0x98, 0x00, 0xEA, 0x2E, 0x00, 0xB4, 0x00, 0x92, 0xBD, 0x00, 0x53, 0x01,
0x87, 0xF7, 0x40, 0xA7, 0x00, 0xBF, 0xB6, 0x00, 0xF0, 0x01, 0x5D, 0x9C, 0x01, 0x24, 0x00,
0xA5, 0xC2, 0x40, 0x2C, 0x00, 0x68, 0xAE, 0x00, 0x32, 0x01, 0x14, 0x4B, 0x40, 0x5A, 0x00,
0x9C, 0xB0, 0x00, 0x81, 0x00, 0x2E, 0x84, 0x40, 0x84, 0x00, 0xE8, 0x34, 0x00, 0xA3, 0x00,
0x7A, 0xA8, 0x40, 0xB6, 0x00, 0xDC, 0xB0, 0x00, 0xDA, 0x01, 0x84, 0x18, 0x01, 0x2D, 0x00,
0x66, 0xD1, 0x01, 0x1E, 0x00, 0x47, 0xE7, 0x40, 0x12, 0x00, 0xE2, 0x48, 0x00, 0x50, 0x00,
0x46, 0x91, 0x00, 0x6F, 0x00, 0x40, 0x91, 0x40, 0x62, 0x00, 0xC2, 0xB6, 0x00, 0x4B, 0x01,
0x40, 0x5E, 0x00, 0x8E, 0x00, 0x3A, 0x8D, 0x00, 0x56, 0x01, 0x7A, 0x6E, 0x00, 0x8E, 0x00,
0x7A, 0xA7, 0x40, 0x76, 0x00, 0xFA, 0x3B, 0x40, 0xA2, 0x00, 0x2A, 0x79, 0x40, 0x8A, 0x00,
0xAA, 0xB2, 0x40, 0x96, 0x00, 0xAA, 0xB4, 0x40, 0x7B, 0x01, 0x40, 0x70, 0x40, 0x86, 0x01,
0x0A, 0x3F, 0x40, 0xAB, 0x00, 0x80, 0xAD, 0x40, 0xAC, 0x00, 0x86, 0xB9, 0x00, 0xB8, 0x00,
0x6E, 0x70, 0x40, 0xB6, 0x00, 0xAA, 0x3B, 0x00, 0x9F, 0x01, 0x28, 0x8D, 0x00, 0xCE, 0x00,
0x42, 0xE8, 0x40, 0xD4, 0x00, 0x2E, 0xEB, 0x00, 0xCE, 0x00, 0x5A, 0xD8, 0x40, 0xF2, 0x00,
0x2A, 0xEE, 0x01, 0x04, 0x00, 0x4E, 0xDC, 0x40, 0xEA, 0x01, 0x82, 0x98, 0x01, 0x20, 0x01,
0x26, 0x25, 0x00, 0x00
};

void printBioAttributes(const CK_ATTRIBUTE attribute) {
    switch (attribute.type) {
    case CKA_VENDOR_RETRY_COUNT_LEFT:
        printf("CKA_VENDOR_RETRY_COUNT_LEFT               %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_VENDOR_MAX_RETRY_COUNT:
        printf("CKA_VENDOR_MAX_RETRY_COUNT                %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_VENDOR_FP_CONVOLUTIONS_COUNT:
        printf("CKA_VENDOR_FP_CONVOLUTIONS_COUNT          %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID:
        printf("CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID    %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_DESTROYABLE:
        printf("CKA_DESTROYABLE                           %s\n",
               *(CK_BBOOL*)attribute.pValue == CK_TRUE ? "TRUE" : "FALSE");
        break;
    case CKA_EXTRACTABLE:
        printf("CKA_EXTRACTABLE                           %s\n",
               *(CK_BBOOL*)attribute.pValue == CK_TRUE ? "TRUE" : "FALSE");
        break;
    case CKA_MODIFIABLE:
        printf("CKA_MODIFIABLE                            %s\n",
               *(CK_BBOOL*)attribute.pValue == CK_TRUE ? "TRUE" : "FALSE");
        break;
    default:
        return;
    }
}

static const char* fingerprintTypeToString(CK_BIO_FINGERPRINT_TYPE ft) {
switch (ft) {
case CK_BIO_FT_UNKNOWN:
return "unknown";
case CK_BIO_FT_RIGHT_THUMB:
return "right_thumb";
case CK_BIO_FT_RIGHT_INDEX:
return "right_index";
case CK_BIO_FT_RIGHT_MIDDLE:
return "right_middle";
case CK_BIO_FT_RIGHT_RING:
return "right_ring";
case CK_BIO_FT_RIGHT_LITTLE:
return "right_little";
case CK_BIO_FT_LEFT_THUMB:
return "left_thumb";
case CK_BIO_FT_LEFT_INDEX:
return "left_index";
case CK_BIO_FT_LEFT_MIDDLE:
return "left_middle";
case CK_BIO_FT_LEFT_RING:
return "left_ring";
case CK_BIO_FT_LEFT_LITTLE:
return "left_little";
default:
return "?";
}
}

#endif // BioCommon_H

Работа напрямую с Рутокен БИО

Получение информации о поддержке биометрической аутентификации 

Файл BioCheckToken.c
#include "BioCommon.h"

/************************************************************************
 * Шаблоны для поиска атрибута поддержки биометрии                      *
 ************************************************************************/
CK_ATTRIBUTE hardwareObjectTemplate[] = {
    { CKA_CLASS, &hardwareFeatureObject, sizeof(hardwareFeatureObject) },
    { CKA_HW_FEATURE_TYPE, &hardwareFeatureTokenInfo,
        sizeof(hardwareFeatureTokenInfo) }
};

CK_ULONG bioAuthSupportedTypes;

CK_ATTRIBUTE attributesTemplate = {
    CKA_VENDOR_BIOMETRIC_AUTHENTICATION, &bioAuthSupportedTypes,
        sizeof(bioAuthSupportedTypes)
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE_PTR features; // Массив найденных объектов характеристик токена
    CK_ULONG featuresCount;        // Количество объектов характеристик в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
        CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Проверить подходит ли целевой токен для работы с биометрией           *
     *************************************************************************/
    printf(" Checking for Biometric Authentication support...\n");
    r = findObjects(functionList, session, hardwareObjectTemplate,
        arraysize(hardwareObjectTemplate), &features, &featuresCount);
    CHECK_AND_LOG("  findObjects", r == 0, "", free_features);
CHECK_AND_LOG(" Features have been found", featuresCount > 0, "", logout);

    rv = functionList->C_GetAttributeValue(session, features[0], &attributesTemplate, 1);
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_features);

    CHECK_RELEASE(" Token supports Biometric Authentication",
        bioAuthSupportedTypes & BIOMETRIC_AUTHENTICATION_FINGERPRINT_CONVOLUTION, errorCode);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под объекты характеристик токена          *
     *************************************************************************/
free_features:
     free(features);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
logout:
     rv = functionList->C_Logout(session);
     CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
close_session:
     rv = functionList->C_CloseSession(session);
     CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
free_slots:
     free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
finalize_pkcs11:
     rv = functionList->C_Finalize(NULL_PTR);
     CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
     CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
     if (errorCode) {
         printf("\n\nSome error occurred. Sample failed.\n");
     } else {
        printf("\n\nSample has been completed successfully.\n");
     }

    return errorCode;
}

Первоначальное внесение набора отпечатков пальцев

Устройство должно поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.

Файл BioInitFingerprint.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона объекта набора отпечатков пальцев               *
 ************************************************************************/
CK_VENDOR_BUFFER fingerprints[] = {
    { initFingerprint, sizeof(initFingerprint) },
};
CK_ULONG fingerprintsCount = 2;
CK_ULONG maxRetryCount = 10;

CK_ATTRIBUTE fingerprintsTemplate[] = {
    { CKA_CLASS, &authObject,
        sizeof(authObject) },        // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) },          // Описание типа аутентификации создаваемого объекта -
                                     // свертка отпечатка пальца
    { CKA_VENDOR_FP_CONVOLUTIONS_COUNT, &fingerprintsCount,
        sizeof(fingerprintsCount) }, // Максимальное количество шаблонов в наборе.
                                     // Максимально разрешенное количество - 3 шаблона.
    { CKA_VENDOR_FP_CONVOLUTIONS, &fingerprints,
        sizeof(fingerprints) },      // Первоначальный набор отпечатков пальцев. Количество объектов
                                     // в массиве должно быть равно от 1 до значения fingerprintsCount.
    { CKA_VENDOR_MAX_RETRY_COUNT, &maxRetryCount,
        sizeof(maxRetryCount) }      // Максимальное количество неуспешных аутентификаций подряд.
                                     // Допустимые значения: от 1 до 10.
};

/************************************************************************
 * Формирование шаблона атрибутов для получения дополнительной          *
 * информации об объекте набора отпечатков пальцев                      *
 ************************************************************************/
CK_ULONG retryCountLeft;
CK_ULONG fpConvolutionId;
CK_BBOOL isDestroyable;
CK_BBOOL isExtractable;
CK_BBOOL isModifiable;

CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_RETRY_COUNT_LEFT, &retryCountLeft,
      sizeof(retryCountLeft) }, // Количество оставшихся попыток неуспешной аутентификации
                                // при помощи объекта.
                                // Сбрасывается до значения maxRetryCount при успешной аутентификации.
                                // При значении 0 объект является заблокированным, и не может
                                // использоваться для аутентификации до момента разблокировки.

    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
      sizeof(fpConvolutionId) }, // Идентификатор объекта набора отпечатков
    { CKA_DESTROYABLE, &isDestroyable, sizeof(isDestroyable) }, // Разрешено ли уничтожение объекта
                                                                // при помощи `C_DestroyObject`.
                                                                // Должно быть возвращено CK_FALSE

    { CKA_EXTRACTABLE, &isExtractable,
      sizeof(isExtractable) }, // Разрешено ли получение содержимого CKA_VENDOR_FP_CONVOLUTIONS
                               // при помощи `C_GetAttributeValue`. Должно быть возвращено CK_FALSE
    { CKA_MODIFIABLE, &isModifiable,
      sizeof(isModifiable) }, // Разрешено ли изменение содержимого CKA_VENDOR_FP_CONVOLUTIONS
                              // при помощи `C_SetAttributeValue`. Должно быть возвращено CK_TRUE
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE fingerprintsHandle; // Дескриптор набора отпечатков пальцев

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    CK_ULONG i;        // Вспомогательная переменная-счетчик в циклах
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Создать объект набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Creating fingerprints set...\n");
    rv = functionList->C_CreateObject(session, fingerprintsTemplate, arraysize(fingerprintsTemplate),
                                      &fingerprintsHandle);
    CHECK_AND_LOG("  C_CreateObject", rv == CKR_OK, rvToStr(rv), logout);

    printf(" Fingerprints set has been created successfully.\n");

    /*************************************************************************
     * Получить дополнительную информацию о наборе отпечатков пальцев        *
     *************************************************************************/
    printf(" Getting attributes of fingerprints set...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprintsHandle, attributeValueTemplate,
                                           arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Вывести значения атрибутов                                            *
     *************************************************************************/
    for (i = 0; i < arraysize(attributeValueTemplate); ++i) {
        printBioAttributes(attributeValueTemplate[i]);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}


Создание ключевой пары, защищенной отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
BioCreateKeyPair.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) }, // Описание типа аутентификации создаваемого объекта (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона для поиска значения атрибута идентификатора     *
 * в объекте набора отпечатков пальцев                                  *
 ************************************************************************/
CK_ULONG fpConvolutionId;

CK_ATTRIBUTE attributeValueTemplate[] = { { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
                                            sizeof(fpConvolutionId) } };

/*************************************************************************
 * Шаблон для генерации открытого ключа ГОСТ Р 34.10-2012(256)           *
 *************************************************************************/
CK_ATTRIBUTE publicKeyTemplate[] = {
    { CKA_CLASS, &publicKeyObject, sizeof(publicKeyObject) }, // Класс - открытый ключ
    { CKA_LABEL, &publicKeyLabelGost2012_256_1, sizeof(publicKeyLabelGost2012_256_1) - 1 }, // Метка ключа
    { CKA_ID, &keyPairIdGost2012_256_1,
        sizeof(keyPairIdGost2012_256_1) - 1 }, // Идентификатор ключевой пары
// (должен совпадать у открытого и закрытого ключей)
    { CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) }, // Тип ключа - ГОСТ Р 34.10-2012 (256)
    { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) }, // Ключ является объектом токена
    { CKA_PRIVATE, &attributeFalse, sizeof(attributeFalse) }, // Ключ доступен без аутентификации на токене
    { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) }, // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    { CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) } // Параметры алгоритма ГОСТ Р 34.11-2012(256)
};

/*************************************************************************
 * Шаблон для генерации закрытого ключа ГОСТ Р 34.10-2012(256)           *
 * с биометрической аутентификацией                                      *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) }, // Класс - закрытый ключ
    { CKA_LABEL, &privateKeyLabelGost2012_256_1,
        sizeof(privateKeyLabelGost2012_256_1) - 1 }, // Метка ключа
    { CKA_ID, &keyPairIdGost2012_256_1, // Идентификатор ключевой пары.
        sizeof(keyPairIdGost2012_256_1) - 1 }, // Должен совпадать у открытого и закрытого ключей
    { CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) },   // Тип ключа - ГОСТ Р 34.10-2012(256)
    { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) }, // Ключ является объектом токена
    { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue) }, // Ключ доступен только после
                                                            // аутентификации на токене
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) }, // Ключ можно использовать только после биометрической аутентификации
                                   // объектом с заданным id                                    
    { CKA_DERIVE, &attributeTrue, sizeof(attributeTrue) }, // Ключ поддерживает выработку
                                                           // ключей обмена (VKO)
    { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) }, // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    { CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) }, // Параметры алгоритма ГОСТ Р 34.11-2012(256)
    { CKA_START_DATE, &startDate, sizeof(startDate) }, // Дата начала срока действия закрытого ключа
    { CKA_END_DATE, &endDate, sizeof(startDate) }, // Дата окончания срока действия закрытого ключа
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии
    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_MECHANISM_TYPE_PTR mechanisms; // Массив поддерживаемых механизмов
    CK_ULONG mechanismCount;          // Количество поддерживаемых механизмов
    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве
    CK_OBJECT_HANDLE
    publicKey;  // Дескриптор открытого ключа
                // ГОСТ Р 34.10-2012(256) (первая ключевая пара для подписи и обмена ключами)
    CK_OBJECT_HANDLE
    privateKey; // Дескриптор закрытого ключа
                // ГОСТ Р 34.10-2012(256) (первая ключевая пара для подписи и обмена ключами)

    CK_RV rv;   // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;      // Код возврата для функций, возвращающих int
    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах
    int isGostR3410Supported = 0; // Флаг для проверки поддержки токеном CKM_GOSTR3410_KEY_PAIR_GEN
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);
    CHECK_AND_LOG(" Checking available tokens",
slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Получить список поддерживаемых токеном механизмов                     *
     *************************************************************************/
    rv = functionList->C_GetMechanismList(slots[0], NULL_PTR, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList (number of mechanisms)", rv == CKR_OK, rvToStr(rv), free_slots);
    CHECK_AND_LOG(" Checking mechanisms available", mechanismCount > 0,
        " No mechanisms available", free_slots);

    mechanisms = (CK_MECHANISM_TYPE_PTR)malloc(mechanismCount * sizeof(CK_MECHANISM_TYPE));
    CHECK(" Memory allocation for mechanisms", mechanisms != NULL_PTR, free_slots);

    rv = functionList->C_GetMechanismList(slots[0], mechanisms, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList", rv == CKR_OK, rvToStr(rv), free_mechanisms);

    /*************************************************************************
     * Определение поддерживаемых токеном механизмов                         *
     *************************************************************************/
    for (i = 0; i < mechanismCount; ++i) {
        if (mechanisms[i] == CKM_GOSTR3410_KEY_PAIR_GEN) {
            isGostR3410Supported = 1;
            break;
        }
    }

    CHECK_AND_LOG(" Checking CKM_GOSTR3410_KEY_PAIR_GEN support", isGostR3410Supported,
                  "CKM_GOSTR3410_KEY_PAIR_GEN isn`t supported!\n", free_mechanisms);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /*************************************************************************
     * Получение значения атрибута идентификатора из первого найденного      *
     * объекта набора отпечатков пальцев                                     *
     *************************************************************************/
    printf(" Getting fingerprints set convolution ID value...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[0],
        attributeValueTemplate, arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Сгенерировать ключевую пару ГОСТ Р 34.10-2012(256)                    *
     *************************************************************************/
    printf(" Generating GOST R 34.10-2012(256) exchange key pairs...\n");
    rv = functionList->C_GenerateKeyPair(session, &gostR3410_2012_256KeyPairGenMech, publicKeyTemplate,
arraysize(publicKeyTemplate), privateKeyTemplate, arraysize(privateKeyTemplate),
&publicKey, &privateKey);
    CHECK_AND_LOG("  C_GenerateKeyPair", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;
    printf("Generation has been completed successfully.\n");

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под объекты набора отпечатков пальцев     *
     *************************************************************************/
    free_fingerprints:
        free(fingerprints);

   
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
  logout:      
rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/
    free_mechanisms:
        free(mechanisms);

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Проверка, что закрытый ключ (ключевая пара) защищен отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
  3. Содержать объект ключевой пары, защищённый биометрией. Создание объекта описано в примере BioCreateKeyPair.c.
Файл BioCheckKeyPair.c
#include <BioCommon.h>

/*************************************************************************
 * Шаблон для поиска атрибута идентификатора отпечатка пальцев           *
 * в объекте закрытого ключа                                             *
 *************************************************************************/
CK_ATTRIBUTE attrConvolutionsIdTemplate[] = { { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, NULL_PTR, 0 } };

/*************************************************************************
 * Шаблон для поиска атрибута идентификатора пары в объекте              *
 * закрытого ключа                                                       *
 *************************************************************************/
CK_ATTRIBUTE attrPairIdTemplate[] = { { CKA_ID, NULL_PTR, 0 } };

/*************************************************************************
 * Шаблон для поиска закрытого ключа для цифровой подписи                *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) }, // Класс - закрытый ключ
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE_PTR privateKeys; // Массив дескрипторов объектов закрытых ключей
    CK_ULONG privateKeysCount; // Количество дескрипторов объектов закрытых ключей

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11

    int r; // Код возврата для функций, возвращающих int

    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах

    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск всех закрытых ключей. Также можно сначала найти открытый ключ   *
     * пары по атрибуту CKA_VALUE и затем найти закрытый ключ по атрибуту    *
     * CKA_ID открытого ключа                                                *
     *************************************************************************/
    printf(" Getting private keys...\n");
    r = findObjects(functionList, session, privateKeyTemplate, arraysize(privateKeyTemplate),
        &privateKeys, &privateKeysCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_privateKeys);
CHECK_AND_LOG(" Private keys (key pairs) have been found", privateKeysCount > 0, "", logout);

    /*************************************************************************
     * Проверка всех найденных закрытых ключей (ключевых пар)                *
     * на защиту отпечатком пальцев                                          *
     *************************************************************************/
    printf(" Checking private keys (key pairs) for protection by Biometric Authentication...\n");
    for (i = 0; i < privateKeysCount; ++i) {
        free(attrPairIdTemplate->pValue);
        attrPairIdTemplate->pValue = NULL_PTR;

        /*************************************************************************
         * Получение длины значения атрибута идентификатора пары ключей          *
         *************************************************************************/
        rv = functionList->C_GetAttributeValue(session, privateKeys[i], attrPairIdTemplate, 1);
        CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_privateKeys);

        /*************************************************************************
         * Выделение памяти под значение атрибута идентификатора пары ключей     *
         *************************************************************************/
        attrPairIdTemplate->pValue = (CK_VOID_PTR)malloc(attrPairIdTemplate->ulValueLen);
        CHECK_AND_LOG("  Memory allocation for pair ID value",
            attrPairIdTemplate->pValue != NULL, rvToStr(rv), free_privateKeys);

        /*************************************************************************
         * Получение значения атрибута идентификатора пары                       *
         *************************************************************************/
        rv = functionList->C_GetAttributeValue(session, privateKeys[i], attrPairIdTemplate, 1);
        CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_pairId);

        /*************************************************************************
         * Получение атрибута идентификатора отпечатка пальцев                   *
         *************************************************************************/
        rv = functionList->C_GetAttributeValue(session, privateKeys[i], attrConvolutionsIdTemplate, 1);
        CHECK_RELEASE("  C_GetAttributeValue", rv == CKR_OK, errorCode);

        /**************************************************************************
         * Вывод сообщения с результатом проверки закрытого ключа (ключевой пары) *
         **************************************************************************/
        printf(" Private key (key pair) with ID *%.*s* %s biometric authentication.\n\n",
               (int)attrPairIdTemplate->ulValueLen, (CK_BYTE*)attrPairIdTemplate->pValue,
               (rv == CKR_OK ? " supports" : " dose not support"));
    }
    if (privateKeysCount > 0)
        printf("All private keys (key pairs) are checked.\n");
    else
        printf("No private keys (key pairs) found.\n");

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Очистить память, выделенную под атрибуты объект                       *
     *************************************************************************/
    free_pairId:
        free(attrPairIdTemplate->pValue);

    /*************************************************************************
     * Очистить память, выделенную под объекты                               *
     *************************************************************************/
    free_privateKeys:
        free(privateKeys);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
    logout:
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Использование ключевой пары, защищенной отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
  3. Содержать объект ключевой пары, защищённый биометрией. Создание объекта описано в примере BioCreateKeyPair.c.
Файл BioUseKeyPair.c
#include "BioCommon.h"

/*************************************************************************
 * Данные для хеширования и цифровой подписи                             *
 *************************************************************************/
CK_BYTE data[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) }, // Описание типа аутентификации
// создаваемого объекта (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона для поиска значения атрибута идентификатора     *
 * в объекте набора отпечатков пальцев                                  *
 ************************************************************************/
CK_ULONG fpConvolutionId;

CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId, sizeof(fpConvolutionId) }
};

/*************************************************************************
 * Шаблон для поиска закрытого ключа для цифровой подписи                *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_ID, &keyPairIdGost2012_256_1, sizeof(keyPairIdGost2012_256_1) - 1 }, // ID пары
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) },                // Класс - закрытый ключ
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) }, // ID объекта набора отпечатков пальцев,
                                   // который использовался для биометрической аутентификации
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_MECHANISM_TYPE_PTR mechanisms; // Массив поддерживаемых механизмов
    CK_ULONG mechanismCount;          // Количество поддерживаемых механизмов

    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_OBJECT_HANDLE_PTR privateKeys; // Массив дескрипторов объектов закрытых ключей
    CK_ULONG privateKeysCount; // Количество дескрипторов объектов закрытых ключей

    CK_BYTE_PTR signature; // Указатель на буфер, содержащий цифровую подпись для данных
    CK_ULONG signatureSize; // Размер буфера, содержащего цифровую подпись для данных, в байтах

    CK_BYTE_PTR hash;  // Указатель на временный буфер для хеш-кода от данных
    CK_ULONG hashSize; // Размер временного буфера в байтах

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11

    int r; // Код возврата для функций, возвращающих int

    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах

    int isGostR3410Supported = 0; // Флаг для проверки поддержки токеном CKM_GOSTR3410_KEY_PAIR_GEN

    int fingerprintIndex = -1; // Индекс объекта набора отпечатка пальцев,
                               // соответствующий переданному отпечатку

    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
"C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Получить список поддерживаемых токеном механизмов                     *
     *************************************************************************/
    rv = functionList->C_GetMechanismList(slots[0], NULL_PTR, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList (number of mechanisms)", rv == CKR_OK, rvToStr(rv), free_slots);

    CHECK_AND_LOG(" Checking mechanisms available",
mechanismCount > 0, " No mechanisms available", free_slots);

    mechanisms = (CK_MECHANISM_TYPE_PTR)malloc(mechanismCount * sizeof(CK_MECHANISM_TYPE));
    CHECK(" Memory allocation for mechanisms", mechanisms != NULL_PTR, free_slots);

    rv = functionList->C_GetMechanismList(slots[0], mechanisms, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList", rv == CKR_OK, rvToStr(rv), free_mechanisms);

    /*************************************************************************
     * Определение поддерживаемых токеном механизмов                         *
     *************************************************************************/
    for (i = 0; i < mechanismCount; ++i) {
        if (mechanisms[i] == CKM_GOSTR3410_KEY_PAIR_GEN) {
            isGostR3410Supported = 1;
            break;
        }
    }

    CHECK_AND_LOG(" Checking CKM_GOSTR3410_KEY_PAIR_GEN support", isGostR3410Supported,
                  "CKM_GOSTR3410_KEY_PAIR_GEN isn`t supported!\n", free_mechanisms);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

/*************************************************************************
* Повторная попытка аутентификации для набора отпечатков, *
* обновленного с помощью примера BioUpdateFingerprint *
*************************************************************************/
rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
initFingerprint, sizeof(initFingerprint));

if (rv == CKR_PIN_INCORRECT)
rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
updateFingerprint1, sizeof(updateFingerprint1));
CHECK_AND_LOG(" C_EX_Authenticate", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /************************************************************************
     * Получение значения атрибута идентификатора из первого найденного   *
     * объекта набора отпечатков пальцев                                    *
     ************************************************************************/
    printf(" Getting fingerprints set convolution ID value...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[fingerprintIndex],
        attributeValueTemplate, arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), deauthenticate);

    /*************************************************************************
     * Поиск закрытого ключа, соответствующего набору отпечатков пальцев      *
     *************************************************************************/
    printf(" Getting private keys...\n");
    r = findObjects(functionList, session, privateKeyTemplate,
        arraysize(privateKeyTemplate), &privateKeys, &privateKeysCount);
    CHECK_AND_LOG("  findObjects", r == 0, "", free_privateKeys);
    CHECK_AND_LOG(" Private keys have been found", privateKeysCount > 0, "", deauthenticate);

    /*************************************************************************
     * Вычислить хеш-код данных                                              *
     *************************************************************************/
    printf(" Hashing data...\n");

    /*************************************************************************
     * Инициализировать хеш-функцию                                          *
     *************************************************************************/
    rv = functionList->C_DigestInit(session, &gostR3411_2012_256HashMech);
    CHECK_AND_LOG("  C_DigestInit", rv == CKR_OK, rvToStr(rv), free_privateKeys);

    /*************************************************************************
     * Определить размер хеш-кода                                            *
     *************************************************************************/
    rv = functionList->C_Digest(session, data, sizeof(data), NULL_PTR, &hashSize);
    CHECK_AND_LOG("  C_Digest(get size)", rv == CKR_OK, rvToStr(rv), free_privateKeys);

    /*************************************************************************
     * Вычислить хеш-код данных                                              *
     *************************************************************************/

    hash = (CK_BYTE*)malloc(hashSize * sizeof(CK_BYTE));
    CHECK("  Memory allocation for hash", hash != NULL, free_privateKeys);

    rv = functionList->C_Digest(session, data, sizeof(data), hash, &hashSize);
    CHECK_AND_LOG("  C_Digest (get hash)", rv == CKR_OK, rvToStr(rv), free_hash);

    /*************************************************************************
     * Распечатать буфер, содержащий хеш-код                                 *
     *************************************************************************/
    printf("  Hashed buffer is: \n");
    printHex(hash, hashSize);
    printf("  Hashing has been completed.\n");

    /*************************************************************************
     * Сформировать цифровую подпись данных                                  *
     * по алгоритму ГОСТ Р 34.10-2012(256)                                   *
     *************************************************************************/
    printf(" Signing data...\n");
    /*************************************************************************
     * Инициализировать операцию подписи данных                              *
     *************************************************************************/
    rv = functionList->C_SignInit(session, &gostR3410_2012_256SigVerMech, privateKeys[0]);
    CHECK_AND_LOG("  C_SignInit", rv == CKR_OK, rvToStr(rv), free_hash);

    /*************************************************************************
     * Определить размер данных подписи                                      *
     *************************************************************************/
    rv = functionList->C_Sign(session, hash, hashSize, NULL_PTR, &signatureSize);
    CHECK_AND_LOG("  C_Sign (get size)", rv == CKR_OK, rvToStr(rv), free_hash);

    /*************************************************************************
     * Подписать данные                                                      *
     *************************************************************************/
    signature = (CK_BYTE*)malloc(signatureSize * sizeof(CK_BYTE));
    CHECK("  Memory allocation for signature", signature != NULL, free_hash);

    rv = functionList->C_Sign(session, hash, hashSize, signature, &signatureSize);
    CHECK_AND_LOG("  C_Sign (signing)", rv == CKR_OK, rvToStr(rv), free_signature);

    /*************************************************************************
     * Распечатать буфер, содержащий подпись                                 *
     *************************************************************************/
    printf("  Signature buffer is: \n");
    printHex(signature, signatureSize);
    printf("  Data has been signed successfully.\n");

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под хеш-коды, подпись и объекты           *
     *************************************************************************/
    free_signature:
        free(signature);

    free_hash:
        free(hash);

    free_privateKeys:
        free(privateKeys);

  /************************************************************************
* Деаутентификация при помощи найденного объекта набора отпечатков *
************************************************************************/  
    deauthenticate:
rv = functionListEx->C_EX_Deauthenticate(session, fingerprints[0]);
CHECK_RELEASE_AND_LOG(" C_EX_Deauthenticate", rv == CKR_OK, rvToStr(rv), errorCode);

/************************************************************************
* Очистить память, выделенную под объекты наборов отпечатков *
************************************************************************/
free_fingerprints:
free(fingerprints);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
    logout:
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/
    free_mechanisms:
        free(mechanisms);

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Сброс счетчика попыток применения отпечатка

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
Файл BioResetAttempts.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
      sizeof(authType) }, // Описание типа аутентификации создаваемого объекта (свертка отпечатка пальца)
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    CK_ULONG i;        // Вспомогательная переменная-счетчик в циклах
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
        "C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
    CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /*************************************************************************
     * Сброс счетчика попыток использования у всех объектов                  *
     *************************************************************************/
    printf(" Resetting fingerprints sets use attempts counter...\n");
    for (i = 0; i < fingerprintsCount; ++i) {
        rv = functionListEx->C_EX_UnblockAuthenticator(session, fingerprints[i]);
        CHECK_AND_LOG("  C_EX_UnblockAuthenticator", rv == CKR_OK, rvToStr(rv), logout);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

/*************************************************************************
* Очистить память, выделенную под объекты наборов отпечатков *
*************************************************************************/
free_fingerprints:
free(fingerprints);
    logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Получение информации об объекте набора отпечатков пальцев

Файл BioGetInfo.c
#include <BioCommon.h>

/************************************************************************
 * Шаблоны для поиска объекта набора отпечатков пальцев                 *
 ************************************************************************/
CK_ATTRIBUTE authenticationObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
      sizeof(authType) }, // Описание типа аутентификации, поиск которого
                          // осуществляется (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона атрибутов для получения информации              *
 * об объекте набора отпечатков пальцев                                 *
 ************************************************************************/
CK_ULONG retryCountLeft;
CK_ULONG maxRetryCountLeft;
CK_ULONG fpConvolutionId;
CK_ULONG fingerprintsCount;

CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_RETRY_COUNT_LEFT, &retryCountLeft,
        sizeof(retryCountLeft) }, // Количество оставшихся попыток неуспешной
                                  // аутентификации при помощи объекта. Сбрасывается
                                  // до значения maxRetryCount при успешной
                                  // аутентификации. При значении 0 объект является
                                  // заблокированным, и не может использоваться для
                                  // аутентификации до момента разблокировки
    { CKA_VENDOR_MAX_RETRY_COUNT, &maxRetryCountLeft,
        sizeof(maxRetryCountLeft) }, // Максимальное количество попыток для объекта набора отпечатков
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) },   // Идентификатор объекта набора отпечатков
    { CKA_VENDOR_FP_CONVOLUTIONS_COUNT, &fingerprintsCount,
        sizeof(fingerprintsCount) }, // Максимальное количество шаблонов в наборе
                                     // Максимально разрешенное количество - 3
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsObjectsCount; // Количество дескрипторов объектов набора
                                       // отпечатков пальцев в массиве

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authenticationObjectTemplate,
            arraysize(authenticationObjectTemplate), &fingerprints, &fingerprintsObjectsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsObjectsCount > 0, "", logout);

    /*************************************************************************
     * Получить дополнительную информацию о наборе отпечатков пальцев       *
     *************************************************************************/
    printf(" Getting attributes of fingerprints set...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[0], attributeValueTemplate,
                                           arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Вывести значения атрибутов                                            *
     *************************************************************************/
    for (CK_ULONG i = 0; i < arraysize(attributeValueTemplate); ++i) {
        printBioAttributes(attributeValueTemplate[i]);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под объекты наборов отпечатков            *
     *************************************************************************/
    free_fingerprints:
        free(fingerprints);

    logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Обновление занесенного отпечатка с применением отпечатка пользователя

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.

После выполнения данного примера остальные примеры, использующие для аутентификации изначальный шаблон (initFingerprint), перестанут работать. Создайте новый набор отпечатков (пример BioInitFingerprint.c) или используйте для аутентификации один из новых отпечатков (updateFingerprint1, updateFingerprint2 из примера BioInitFingerprint.c).

Файл BioUpdateFingerprint.c
#include "BioCommon.h"

/************************************************************************
 * Шаблоны для поиска объекта набора отпечатков пальцев                 *
 ************************************************************************/
CK_ATTRIBUTE authenticationObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) },               // Описание типа аутентификации,
                                          // поиск которого осуществляется (свертка отпечатка пальца)
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
         "C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authenticationObjectTemplate,
        arraysize(authenticationObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /*************************************************************************
     * Аутентификация при помощи найденного объекта набора отпечатков        *
     *************************************************************************/
    rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
initFingerprint, sizeof(initFingerprint));
    CHECK_AND_LOG("  C_EX_Authenticate", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Замена существующего набора отпечатков в объекте на новый             *
     *************************************************************************/
    CK_VENDOR_BUFFER newFingerprints[] = {
        { updateFingerprint1, sizeof(updateFingerprint1) },
        { updateFingerprint2, sizeof(updateFingerprint2) }
    };

    CK_ATTRIBUTE fingerprintsUpdateTemplate[] = {
        { CKA_VENDOR_FP_CONVOLUTIONS, &newFingerprints, sizeof(newFingerprints) } };

    rv = functionList->C_SetAttributeValue(session, fingerprints[0], fingerprintsUpdateTemplate, 1);
    CHECK_AND_LOG("  C_SetAttributeValue", rv == CKR_OK, rvToStr(rv), deauthenticate);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");


/************************************************************************
* Деаутентификация при помощи найденного объекта набора отпечатков *
************************************************************************/
deauthenticate:
rv = functionListEx->C_EX_Deauthenticate(session, fingerprints[0]);
CHECK_RELEASE_AND_LOG(" C_EX_Deauthenticate", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под объекты наборов отпечатков            *
     *************************************************************************/
    free_fingerprints:
      free(fingerprints);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
logout:
    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Удаление ключевой пары, защищенной отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
  3. Содержать объект ключевой пары, защищённый биометрией. Создание объекта описано в примере BioCreateKeyPair.c.
Файл BioDeleteKeyPair.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
      sizeof(authType) }, // Описание типа аутентификации создаваемого объекта (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона для поиска значения атрибута идентификатора     *
 * в объекте набора отпечатков пальцев                                  *
 ************************************************************************/
CK_ULONG fpConvolutionId;
CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId, sizeof(fpConvolutionId) }
};

/*************************************************************************
 * Шаблон для генерации открытого ключа ГОСТ Р 34.10-2012(256)           *
 *************************************************************************/
CK_ATTRIBUTE publicKeyTemplate[] = {
    {CKA_CLASS, &publicKeyObject, sizeof(publicKeyObject) }, // Класс - открытый ключ
    {CKA_LABEL, &publicKeyLabelGost2012_256_1, sizeof(publicKeyLabelGost2012_256_1) - 1 }, // Метка ключа
    {CKA_ID, &keyPairIdGost2012_256_1,
        sizeof(keyPairIdGost2012_256_1) - 1 },               // Идентификатор ключевой пары
    {CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) },                 // Тип ключа - ГОСТ Р 34.10-2012(256)
    {CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) },     // Ключ является объектом токена
    {CKA_PRIVATE, &attributeFalse, sizeof(attributeFalse) }, // Ключ доступен без аутентификации на токене
    {CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) },              // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    {CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) }               // Параметры алгоритма ГОСТ Р 34.11-2012(256)
};

/*************************************************************************
 * Шаблон для генерации закрытого ключа ГОСТ Р 34.10-2012(256)           *
 * с биометрической аутентификацией                                      *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) }, // Класс - закрытый ключ
    { CKA_LABEL, &privateKeyLabelGost2012_256_1,
        sizeof(privateKeyLabelGost2012_256_1) - 1 },            // Метка ключа
    { CKA_ID, &keyPairIdGost2012_256_1,
        sizeof(keyPairIdGost2012_256_1) - 1 },                  // Идентификатор ключевой пары
    { CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) },              // Тип ключа - ГОСТ Р 34.10-2012(256)
    { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) }, // Ключ является объектом токена
    { CKA_PRIVATE, &attributeTrue,
        sizeof(attributeTrue) },                // Ключ доступен только после аутентификации на токене
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) },      // Ключ можно использовать только
                                        // после биометрической аутентификации объектом с заданным id
    { CKA_DERIVE, &attributeTrue,
        sizeof(attributeTrue) },        // Ключ поддерживает выработку ключей обмена (VKO)
    { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) }, // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    { CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) }, // Параметры алгоритма ГОСТ Р 34.11-2012(256)
    { CKA_START_DATE, &startDate, sizeof(startDate) }, // Дата начала срока действия закрытого ключа
    { CKA_END_DATE, &endDate, sizeof(startDate) },     // Дата окончания срока действия закрытого ключа
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии
    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended
    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_MECHANISM_TYPE_PTR mechanisms; // Массив поддерживаемых механизмов
    CK_ULONG mechanismCount;          // Количество поддерживаемых механизмов
    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве
    CK_OBJECT_HANDLE_PTR pubKeys; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG pubKeysCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве
    CK_OBJECT_HANDLE_PTR priKeys; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG priKeysCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r; // Код возврата для функций, возвращающих int
    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах

    int isGostR3410Supported = 0; // Флаг для проверки поддержки токеном CKM_GOSTR3410_KEY_PAIR_GEN
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
"C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);
    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Получить список поддерживаемых токеном механизмов                     *
     *************************************************************************/
    rv = functionList->C_GetMechanismList(slots[0], NULL_PTR, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList (number of mechanisms)", rv == CKR_OK, rvToStr(rv), free_slots);
    CHECK_AND_LOG(" Checking mechanisms available",
mechanismCount > 0, " No mechanisms available", free_slots);

    mechanisms = (CK_MECHANISM_TYPE_PTR)malloc(mechanismCount * sizeof(CK_MECHANISM_TYPE));
    CHECK(" Memory allocation for mechanisms", mechanisms != NULL_PTR, free_slots);

    rv = functionList->C_GetMechanismList(slots[0], mechanisms, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList", rv == CKR_OK, rvToStr(rv), free_mechanisms);

    /*************************************************************************
     * Определение поддерживаемых токеном механизмов                         *
     *************************************************************************/
    for (i = 0; i < mechanismCount; ++i) {
        if (mechanisms[i] == CKM_GOSTR3410_KEY_PAIR_GEN) {
            isGostR3410Supported = 1;
            break;
        }
    }

    CHECK_AND_LOG(" Checking CKM_GOSTR3410_KEY_PAIR_GEN support", isGostR3410Supported,
                  "CKM_GOSTR3410_KEY_PAIR_GEN isn`t supported!\n", free_mechanisms);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /************************************************************************
     * Получение значения атрибута идентификатора из первого найденного     *
     * объекта набора отпечатков пальцев                                    *
     ************************************************************************/
    printf(" Getting fingerprints set convolution ID value...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[0], attributeValueTemplate,
                                           arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    rv = functionListEx->C_EX_Authenticate(session, fingerprints[0], 
initFingerprint, sizeof(initFingerprint));

/************************************************************************
* Повторная попытка аутентификации для набора отпечатков, обновленного *
* с помощью примера BioUpdateFingerprint *
************************************************************************/
if (rv == CKR_PIN_INCORRECT) rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
updateFingerprint1, sizeof(updateFingerprint1));
CHECK_AND_LOG(" C_EX_Authenticate", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Поиск объектов ключевой пары на токене.                               *
     * Предполагается наличие одной ключевой пары с заданными параметрами    *
     *************************************************************************/
    printf(" Getting private key...\n");
    r = findObjects(functionList, session, privateKeyTemplate,
        arraysize(privateKeyTemplate), &priKeys, &priKeysCount);
CHECK_AND_LOG(" findObjects", (r == 0), "", free_prikeys);
CHECK_AND_LOG(" Private keys have been found", priKeysCount > 0, "", deauthenticate);

    printf(" Getting public key...\n");
    r = findObjects(functionList, session, publicKeyTemplate,
        arraysize(publicKeyTemplate), &pubKeys, &pubKeysCount);
    CHECK_AND_LOG(" findObjects", (r == 0), "", free_pubkeys);
CHECK_AND_LOG(" Public keys have been found", pubKeysCount > 0, "", free_prikeys);

    /*************************************************************************
     * Удаление объектов ключевой пары с токена                              *
     *************************************************************************/
    printf(" Deleting private key...\n");
    rv = functionList->C_DestroyObject(session, priKeys[0]);
    CHECK_AND_LOG("  C_DestroyObject", rv == CKR_OK, rvToStr(rv), free_pubkeys);

    printf(" Deleting public key...\n");
    rv = functionList->C_DestroyObject(session, pubKeys[0]);
    CHECK_AND_LOG("  C_DestroyObject", rv == CKR_OK, rvToStr(rv), free_pubkeys);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;
    printf("Generation has been completed successfully.\n");

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");
   
    /*************************************************************************
     * Очистить память, выделенную под объекты открытых ключей               *
     *************************************************************************/
free_pubkeys:
        free(pubKeys);

    /*************************************************************************
     * Очистить память, выделенную под объекты закрытых ключей               *
     *************************************************************************/
free_prikeys:
        free(priKeys);


/*************************************************************************
* Деаутентификация при помощи найденного объекта набора отпечатков *
*************************************************************************/
deauthenticate:
rv = functionListEx->C_EX_Deauthenticate(session, fingerprints[0]);
CHECK_RELEASE_AND_LOG(" C_EX_Deauthenticate", rv == CKR_OK, rvToStr(rv), errorCode);


    /*************************************************************************
     * Очистить память, выделенную под объекты набора отпечатков пальцев     *
     *************************************************************************/
free_fingerprints:
        free(fingerprints);
 
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
logout:
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/
    free_mechanisms:
        free(mechanisms);

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}


Работа с Рутокен БИО и сканерами в PKCS#11 через BioLib

Получение cписка доступных адаптеров сканеров

Файл CBioListScannersAdapters.c
#include <BioCommon.h>

int main(void) {
HMODULE module; // Дескриптор загруженной библиотеки PKCS#11

CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST_BIO
CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

CK_BIO_SCANNERS_ADAPTER_INFO_PTR adaptersInfo; // Массив информации об адаптерах сканеров
CK_ULONG adaptersInfoCount; // Размер массива информации об адаптерах сканеров

CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
int errorCode = 1; // Флаг ошибки

/*************************************************************************
* Выполнить действия для начала работы с библиотекой PKCS#11 *
*************************************************************************/
printf("Initialization...\n");

/*************************************************************************
* Загрузить библиотеку *
*************************************************************************/
module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
CHECK(" LoadLibrary", module != NULL, exit);

/*************************************************************************
* Получить адрес функции запроса структуры с указателями на функции *
*************************************************************************/
getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

/*************************************************************************
* Получить структуру с указателями на функции *
*************************************************************************/
rv = getFunctionList(&functionList);
CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

/*************************************************************************
* Получить адрес функции запроса структуры с указателями на *
* биометрические функции *
*************************************************************************/
getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

/*************************************************************************
* Получить структуру с указателями на биометрические функции *
*************************************************************************/
rv = getFunctionListBio(&functionListBio);
CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

/*************************************************************************
* Инициализировать библиотеку *
*************************************************************************/
rv = functionList->C_Initialize(&initArgs);
CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

/*************************************************************************
* Инициализировать биометрический функционал *
*************************************************************************/
rv = functionListBio->C_BIO_Initialize(0);
CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

/*************************************************************************
* Получить информацию об адаптерах сканеров *
*************************************************************************/
rv = functionListBio->C_BIO_ListScannersAdapters(NULL, &adaptersInfoCount);
CHECK_AND_LOG(" C_BIO_ListScannersAdapters", rv == CKR_OK, rvToStr(rv), finalize_bio);

adaptersInfo = (CK_BIO_SCANNERS_ADAPTER_INFO_PTR)
malloc(adaptersInfoCount * sizeof(CK_BIO_SCANNERS_ADAPTER_INFO));
CHECK(" Memory allocation for adapters info", adaptersInfo != NULL, finalize_bio);

rv = functionListBio->C_BIO_ListScannersAdapters(adaptersInfo, &adaptersInfoCount);
CHECK_AND_LOG(" C_BIO_ListScannersAdapters", rv == CKR_OK, rvToStr(rv), free_adaptersInfo);

/*************************************************************************
* Вывести информацию об адаптерах сканеров *
*************************************************************************/
printf("\n");
for (CK_ULONG i = 0; i < adaptersInfoCount; ++i) {
printf("%3lu. %-10s: %s \n", i + 1, adaptersInfo[i].name,
adaptersInfo[i].available ? "available" : "not available");
}
printf("\n");

/*************************************************************************
* Выставить признак успешного завершения программы *
*************************************************************************/
errorCode = 0;

/*************************************************************************
* Выполнить действия для завершения работы с библиотекой PKCS#11 *
*************************************************************************/
printf("\nFinalizing... \n");

/*************************************************************************
* Очистить память, выделенную под информацию об адаптерах сканеров *
*************************************************************************/
free_adaptersInfo:
free(adaptersInfo);

/*************************************************************************
* Деинициализировать биометрические функции *
*************************************************************************/
finalize_bio:
rv = functionListBio->C_BIO_Finalize(NULL_PTR);
CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

/*************************************************************************
* Деинициализировать библиотеку *
*************************************************************************/
finalize_pkcs11:
rv = functionList->C_Finalize(NULL_PTR);
CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

/*************************************************************************
* Выгрузить библиотеку из памяти *
*************************************************************************/
unload_pkcs11:
CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
if (errorCode) {
printf("\n\nSome error occurred. Sample failed.\n");
} else {
printf("\n\nSample has been completed successfully.\n");
}

return errorCode;
}

Получение cписка доступных сканеров

Файл CBioListScanners.c
#include <BioCommon.h>

int main(void) {
    HMODULE module; // Дескриптор загруженной библиотеки PKCS#11

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_BIO_SCANNER_INFO_PTR scannersInfo; // Массив информации о сканерах
    CK_ULONG scannersInfoCount;           // Размер массива информации о сканерах

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11           *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                                *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции           *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать биометрический функционал                           *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    /*************************************************************************
     * Получить информацию о сканерах                                        *
     *************************************************************************/
    rv = functionListBio->C_BIO_ListScanners(NULL, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), finalize_bio);

    if (scannersInfoCount == 0) {
        printf("\nNo scanners available!\n\n");
        goto finalize_bio;
    }

    scannersInfo = (CK_BIO_SCANNER_INFO_PTR)malloc(scannersInfoCount * sizeof(CK_BIO_SCANNER_INFO));
    CHECK(" Memory allocation for scanners info", scannersInfo != NULL, finalize_bio);

    rv = functionListBio->C_BIO_ListScanners(scannersInfo, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), free_scannersInfo);

    /*************************************************************************
     * Вывести информацию о сканерах                                        *
     *************************************************************************/
    printf("\n");
    for (CK_ULONG i = 0; i < scannersInfoCount; ++i) {
        printf("%3lu. id:%3lu (%s) \n", i + 1, scannersInfo[i].id, scannersInfo[i].adapterName);
    }

    printf("\n");

    /*************************************************************************
     * Выставить признак успешного завершения программы                     *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под информацию о сканерах                 *
     *************************************************************************/
free_scannersInfo:
    free(scannersInfo);

    /*************************************************************************
     * Деинициализировать биометрический функционал                         *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}

Установка сканера по умолчанию

Файл CBioSetDefaultScanner.c
#include <BioCommon.h>

int main(void) {
    HMODULE module; // Дескриптор загруженной библиотеки PKCS#11

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_BIO_SCANNER_INFO_PTR scannersInfo; // Массив информации о сканерах
    CK_ULONG scannersInfoCount;           // Размер массива информации о сканерах

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11           *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                          *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                               *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать биометрический функционал                           *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    /*************************************************************************
     * Получить информацию о сканерах                                       *
     *************************************************************************/
    rv = functionListBio->C_BIO_ListScanners(NULL, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), finalize_bio);

    if (scannersInfoCount == 0) {
        printf("\nNo scanners available!\n\n");
        goto finalize_bio;
    }

    scannersInfo = (CK_BIO_SCANNER_INFO_PTR)malloc(scannersInfoCount * sizeof(CK_BIO_SCANNER_INFO));
    CHECK(" Memory allocation for scanners info", scannersInfo != NULL, finalize_bio);

    rv = functionListBio->C_BIO_ListScanners(scannersInfo, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), free_scannersInfo);

    /*************************************************************************
     * Вывести информацию о сканерах                                         *
     *************************************************************************/
    printf("\n");
    for (CK_ULONG i = 0; i < scannersInfoCount; ++i) {
        printf("%3lu. id:%3lu (%s) \n", i + 1, scannersInfo[i].id, scannersInfo[i].adapterName);
    }
    printf("\n");

    /*************************************************************************
     * Задать сканер по умолчанию                                            *
     *************************************************************************/
    int scannerNumber = 0;
    printf("\nPrint scanner number to set it default (or 0 reset default) ->");
    scanf("%d", &scannerNumber);
    if (scannerNumber < 0 || scannerNumber > (int)(scannersInfoCount)) {
        printf("Invalid scanner number!\n");
        goto free_scannersInfo;
    }

    if (scannerNumber == 0) {
        rv = functionListBio->C_BIO_SetDefaultScanner(NULL_PTR);
    } else {
        rv = functionListBio->C_BIO_SetDefaultScanner(&scannersInfo[scannerNumber - 1]);
    }
    CHECK_AND_LOG(" C_BIO_SetDefaultScanner", rv == CKR_OK, rvToStr(rv), free_scannersInfo);

    /*************************************************************************
     * Выставить признак успешного завершения программы                     *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11       *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную информацию об адаптерах сканеров          *
     *************************************************************************/
free_scannersInfo:
    free(scannersInfo);

    /*************************************************************************
     * Деинициализировать биометрический функционал                          *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}

Помещение отпечатка пальца на Рутокен

Устройство должно поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.


Файл CBioSetFingerprint.c
#include <BioCommon.h>

int main(void) {

    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии
    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO

    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio
    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11

    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/

    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/

    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/

    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * биометрические функции                                                *
     *************************************************************************/

    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/

    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);
    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                      *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);
    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                           *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Администратора                              *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);

    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Инициализировать биометрический функционал                           *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Проверить наличие сканеров для начала работы                          *
     *************************************************************************/

    CK_ULONG scannersCount = 0;
    rv = functionListBio->C_BIO_ListScanners(NULL, &scannersCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), finalize_bio);

    if (scannersCount == 0) {
        printf("\n\nCan't set fingerprint without scanner. Sample will be finished.\n\n");
        goto finalize_bio;
    }

    /*************************************************************************
     * Получить информацию об отпечатке                                      *
     *************************************************************************/
    CK_BIO_FINGERPRINT_INFO fpInfo;
    CK_ULONG fpCount;
    rv = functionListBio->C_BIO_GetFingerprintInfo(session, &fpInfo, NULL, &fpCount);

    if (rv != CKR_BIO_FINGERPRINT_NOT_FOUND) {
        printf("\n\nUpdating fingerprint\nAuthentication needed\n\n");
        rv = functionListBio->C_BIO_Authenticate(session, 0, 0, 0, 0);
        CHECK_AND_LOG(" C_BIO_Authenticate", rv == CKR_OK, rvToStr(rv), finalize_bio);
    } else {
        printf("\n\nCreating new fingerprint \n\n");
    }

    /*************************************************************************
     * Создать или обновить отпечаток                                       *
     *************************************************************************/
    CK_BIO_FINGERPRINT_SCAN_PARAMS scanParams[] = {
        { CK_BIO_FT_LEFT_THUMB, 4 },
        { CK_BIO_FT_LEFT_INDEX, 4 },
        { CK_BIO_FT_LEFT_MIDDLE, 4 },
    };

    CK_ULONG scanParamsCount = sizeof(scanParams) / sizeof(CK_BIO_FINGERPRINT_SCAN_PARAMS);
    CK_BIO_FINGERPRINT_SCAN_STATUS_PTR status = (CK_BIO_FINGERPRINT_SCAN_STATUS_PTR)
malloc(scanParamsCount * sizeof(CK_BIO_FINGERPRINT_SCAN_STATUS));

    CHECK(" Memory allocation for scan status", status != NULL, finalize_bio);
    CK_ULONG statusCount = scanParamsCount;
    CK_BIO_FINGERPRINT_TYPE nextToScan;

    rv = functionListBio->C_BIO_SetFingerprintInit(session, scanParams, scanParamsCount, &nextToScan);
    CHECK_AND_LOG(" C_BIO_SetFingerprintInit", rv == CKR_OK, rvToStr(rv), free_scanStatus);

    while (1) {
        rv = functionListBio->C_BIO_SetFingerprintStatus(session, status, &statusCount);
        CHECK_AND_LOG(" C_BIO_SetFingerprintStatus", rv == CKR_OK, rvToStr(rv), free_scanStatus);
        printf("\nStatus:\n");
        for (size_t i = 0; i < statusCount; ++i) {
            printf("\nType %s: %lu / %lu \n", fingerprintTypeToString(status[i].type),
status[i].currentScansCount, status[i].targetScansCount);
        }

        if (nextToScan == CK_BIO_FT_UNKNOWN) {
            break;
        }
        printf("\nNext: %s \n", fingerprintTypeToString(nextToScan));
        rv = functionListBio->C_BIO_SetFingerprintScan(session, 0, &nextToScan);

        if (rv == CKR_OK) {
            printf("Successfully scanned\n");
        } else if (rv == CKR_BIO_UNACCEPTABLE_FINGERPRINT) {
            printf("Fingerprint not recognized. Try again\n");
        } else {
            printf("C_BIO_SetFingerprintScan failed");
            goto free_scanStatus;
        }
    }

    CK_ULONG fingerprintId = 0;
    rv = functionListBio->C_BIO_SetFingerprintFinal(session, &fingerprintId);
    CHECK_AND_LOG(" C_BIO_SetFingerprintFinal", rv == CKR_OK, rvToStr(rv), free_scanStatus);

    printf("\n\nFingerprint was set correctly, fingerprint id: %lu\n", fingerprintId);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11       *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под параметры отпечатков                 *
     *************************************************************************/

free_scanStatus:
    free(status);

    /*************************************************************************
     * Деинициализировать биометрический функционал                          *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/

    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                      *
     *************************************************************************/

close_session:
    rv = functionList->C_CloseSession(session);
    CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                      *
     *************************************************************************/
free_slots:
    free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }
    return errorCode;
}

Получение информации об отпечатке пальца

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
Файл CBioGetFingerprintInfo.c
#include <BioCommon.h>

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_BIO_FINGERPRINT_INFO fingerprintInfo;   // информация об отпечатке
    CK_BIO_FINGERPRINT_SCAN_PARAMS_PTR params; // параметры скана отпечатка
    CK_ULONG paramsCount; // количество параметров скана отпечатка

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                               *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                  *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                      *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                           *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Инициализировать биометрический функционал                            *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Получить информацию об отпечатке                                      *
     *************************************************************************/
    rv = functionListBio->C_BIO_GetFingerprintInfo(session, &fingerprintInfo, NULL, &paramsCount);
    CHECK_AND_LOG(" C_BIO_GetFingerprintInfo", rv == CKR_OK, rvToStr(rv), finalize_bio);
    CHECK_AND_LOG(" Got fingerprints count", paramsCount != 0, "", finalize_bio);

    params =
(CK_BIO_FINGERPRINT_SCAN_PARAMS_PTR)malloc(paramsCount * sizeof(CK_BIO_FINGERPRINT_SCAN_PARAMS));
    CHECK(" Memory allocation for fingerprint params", params != NULL, finalize_bio);

    rv = functionListBio->C_BIO_GetFingerprintInfo(session, &fingerprintInfo, params, &paramsCount);
    CHECK_AND_LOG(" C_BIO_GetFingerprintInfo", rv == CKR_OK, rvToStr(rv), free_params);

    /*************************************************************************
     * Вывести информацию об отпечатке                                       *
     *************************************************************************/
    printf(
        "\n\nGot fingerprint info:\n"
        "fingerprintId: %lu\nretryCountLeft: %lu\nmaxRetryCount: %lu\n"
        "type:%lu\n",
        fingerprintInfo.fingerprintId, fingerprintInfo.retryCountLeft, fingerprintInfo.maxRetryCount,
        fingerprintInfo.type);

    for (size_t i = 0; i < paramsCount; i++) {
        printf("finger %zu / %lu: type: %s, targetScansCount: %lu\n", (i + 1), paramsCount,
               fingerprintTypeToString(params[i].type), params[i].targetScansCount);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                     *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под параметры отпечатков                  *
     *************************************************************************/
free_params:
    free(params);

    /*************************************************************************
     * Деинициализировать биометрический функционал                           *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

logout:
    /*************************************************************************
     * Сбросить права доступа                                                 *
     *************************************************************************/
    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                        *
     *************************************************************************/
close_session:
    rv = functionList->C_CloseSession(session);
    CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                      *
     *************************************************************************/
free_slots:
    free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                          *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                         *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}


Разблокировка использования отпечатков пальцев

Устройство должно поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.

Файл  CBioUnblockFingerprint.c
#include <BioCommon.h>

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11           *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                               *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                           *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Администратора                              *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Инициализировать биометрический функционал                            *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Разблокировать отпечаток                                             *
     *************************************************************************/

    rv = functionListBio->C_BIO_UnblockFingerprint(session);
    CHECK_AND_LOG(" C_BIO_UnblockFingerprint", rv == CKR_OK, rvToStr(rv), finalize_bio);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11       *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Деинициализировать биометрический функционал                         *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
close_session:
    rv = functionList->C_CloseSession(session);
    CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                      *
     *************************************************************************/
free_slots:
    free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                       *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}

Полный список примеров, который есть в комплекте SDK (/pkcs/samples): 

Перед запуском примеров необходимо отформатировать Рутокен БИО.

Сделать это можно в Центре управления Рутокен (статьи про форматирование на Windows и Linux) или с помощью функции C_EX_InitToken.

Рекомендуется запускать примеры в том порядке, в котором они представлены в документе.

Иной порядок запуска может вызвать ошибки.

Вспомогательные файлы

Файл win2nix.h. Переопределение функций Windows для *nix-платформ
#pragma once

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _WIN32
    #include <windows.h>

typedef HANDLE mutex_t;
#else
    #include <pthread.h>

    #define uintptr_t pthread_t

typedef pthread_mutex_t mutex_t;
#endif

typedef struct {
    void (*func)(void*);
    void* arg;
} thread_args;



static
#ifdef _WIN32
    unsigned __stdcall
#else
    void*
#endif
    wrapperRunner(void* arg) {
    thread_args* th = (thread_args*)arg;
    th->func(th->arg);
    free(th);
#ifdef _WIN32
    _endthreadex(0);
    return 0;
#else
    return NULL;
#endif
}

static int createThread(uintptr_t* thread, void (*funct)(void*), void* arg) {
    thread_args* th = (thread_args*)malloc(sizeof(thread_args));

    if (th == NULL) {
        return 1;
    }

    th->arg = arg;
    th->func = funct;
#ifdef _WIN32
    *thread = _beginthreadex(NULL, 0, wrapperRunner, th, 0, NULL);
    if (*thread == 0)
#else
    if (pthread_create(thread, NULL, wrapperRunner, th))
#endif
    {
        free(th);
        return 1;
    }

    return 0;
}

static int joinThread(uintptr_t thread) {
#ifdef _WIN32
    DWORD rv1 = WaitForSingleObject((HANDLE)thread, INFINITE);
    int rv = !CloseHandle((HANDLE)thread) || rv1;
#else
    int rv = pthread_join(thread, NULL);
#endif
    return !!rv;
}

static int createMutex(mutex_t* mutex) {
#ifdef _WIN32
    *mutex = CreateMutex(NULL, FALSE, NULL);
    if (!*mutex) {
        return 1;
    }
#else
    if (pthread_mutex_init(mutex, NULL)) {
        return 1;
    }
#endif
    return 0;
}

static int destroyMutex(mutex_t* mutex) {
#ifdef _WIN32
    if (!CloseHandle(*mutex)) {
        return 1;
    }
#else
    if (pthread_mutex_destroy(mutex)) {
        return 1;
    }
#endif
    return 0;
}

static int lockMutex(mutex_t* mutex) {
#ifdef _WIN32
    if (WaitForSingleObject(*mutex, INFINITE) != WAIT_OBJECT_0) {
        return 1;
    }
#else
    if (pthread_mutex_lock(mutex)) {
        return 1;
    }
#endif
    return 0;
}

static int unlockMutex(mutex_t* mutex) {
#ifdef _WIN32
    if (!ReleaseMutex(*mutex)) {
        return 1;
    }
#else
    if (pthread_mutex_unlock(mutex)) {
        return 1;
    }
#endif
    return 0;
}

#if defined(__unix__) || defined(__APPLE__)

    #include <dlfcn.h>

    #include "wintypes.h"

typedef void* HMODULE;

static HMODULE LoadLibrary(const char* path) {
    return dlopen(path, RTLD_NOW);
}

static BOOL FreeLibrary(HMODULE module) {
    // Возвращаемое значение инвертируется, чтобы соответствовать поведению Windows
    return !dlclose(module);
}

static ptrdiff_t GetProcAddress(HMODULE module, const char* proc_name) {
    return (ptrdiff_t)(dlsym(module, proc_name));
}

#endif // __unix__ || __APPLE__

Файл wintypes.h. Определение типов данных для *nix-платформ
#pragma once

#ifndef DWORD
typedef unsigned long DWORD;
#endif

#ifndef LONG
typedef long LONG;
#endif

#ifndef BYTE
typedef unsigned char BYTE;
#endif

#ifndef BOOL
typedef int BOOL;
#endif

#ifndef PBYTE
typedef BYTE* PBYTE;
#endif

#ifndef LPBYTE
typedef BYTE* LPBYTE;
#endif

#ifndef PVOID
typedef void* PVOID;
#endif

#ifndef IN
    #define IN
#endif

#ifndef OUT
    #define OUT
#endif

Файл Common.h. Объявление констант для работы с Рутокен при помощи библиотеки PKCS#11
на языке C

#ifndef Common_H
#define Common_H
/**************************************************************************
 * Включение файлов:                                                      *
 *  - stdio.h - для доступа к библиотеке стандартного ввода/вывода        *
 *  - Windows.h - для доступа к функциям Win32API                         *
 *  - WinCrypt.h - для доступа к функциям CryptoAPI                       *
 *  - process.h - для доступа к функциям управления потоками и процессами *
 *  - time.h - для доступа к функциям для работы со временем              *
 *  - win2nix.h - для переопределения функций Windows для *nix-платформ   *
 *  - wintypes.h - для переопределения типов данных Windows для           *
 *    *nix-платформ                                                       *
 *  - rtPKCS11.h - для доступа к функциям PKCS#11                         *
 **************************************************************************/
// clang-format off
#ifdef _WIN32
    #include <stdio.h>
    #include <Windows.h>
    #include <WinCrypt.h>
    #include <process.h>
    #include <time.h>
#endif
// clang-format on

#include "win2nix.h"
#include "wintypes.h"

#include <rtpkcs11.h>

#include <stdlib.h>

/************************************************************************
 * Макросы                                                              *
 ************************************************************************/
/* Имя библиотеки PKCS#11 */
#ifdef _WIN32
    /* Библиотека для Рутокен S и Рутокен ЭЦП, поддерживает только алгоритмы RSA */
    #define PKCS11_LIBRARY_NAME "rtPKCS11.dll"
    /* Библиотека только для Рутокен ЭЦП, поддерживает алгоритмы ГОСТ и RSA */
    #define PKCS11ECP_LIBRARY_NAME "rtPKCS11ECP.dll"
#endif
#ifdef __unix__
    /* Библиотека только для Рутокен ЭЦП, поддерживает алгоритмы ГОСТ и RSA */
    #define PKCS11_LIBRARY_NAME "librtpkcs11ecp.so"
    #define PKCS11ECP_LIBRARY_NAME "librtpkcs11ecp.so"
#endif
#ifdef __APPLE__
    /* Библиотека только для Рутокен ЭЦП, поддерживает алгоритмы ГОСТ и RSA */
    #define PKCS11_LIBRARY_NAME "rtpkcs11ecp.framework/rtpkcs11ecp"
    #define PKCS11ECP_LIBRARY_NAME "rtpkcs11ecp.framework/rtpkcs11ecp"
#endif

#ifndef TOKEN_TYPE_RUTOKEN
    #define TOKEN_TYPE_RUTOKEN 0x3
#endif

#ifdef _WIN32
    #define HAVEMSCRYPTOAPI
#endif

/* Вычисление размера массива */
#define arraysize(a) (sizeof(a) / sizeof(a[0]))

/* Максимальный размер массива с дескрипторами */
#define MAX_OBJECTS_ARRAY_SIZE 100

/* Предопределенная константа RSA */
#define RSAENH_MAGIC_RSA1 0x31415352

/* Размер публичного ECDSA ключа в DER формате в байтах */
#define ECDSA_DER_KEY_SIZE 67

/* Размер симметричного ключа в DER формате в байтах */
#define GENERIC_SECRET_KEY_SIZE 64

/* Размер симметричного ключа ГОСТ 28147-89 в байтах */
#define GOST_28147_KEY_SIZE 32

/* Размер открытого ключа ГОСТ Р 34.10-2001 в байтах */
#define GOST_3410_KEY_SIZE 64

/* Размер открытого ключа ГОСТ Р 34.10-2012(256) в байтах */
#define GOST_3410_12_256_KEY_SIZE 64

/* Размер открытого ключа ГОСТ Р 34.10-2012(512) в байтах */
#define GOST_3410_12_512_KEY_SIZE 128

/* Размер симметричного ключа KEG в байтах */
#define KEG_KEY_SIZE 64

/* Размер синхропосылки в байтах */
#define UKM_LENGTH 8

/* Размер UKM для KEG 256 в байтах */
#define UKM_KEG_256_LENGTH 24

/* Размер UKM для KEG 512 в байтах */
#define UKM_KEG_512_LENGTH 16

/* Размер блока в байтах */
#define GOST28147_89_BLOCK_SIZE 8

/* Максимальное количество попыток ввода PIN-кода Администратора */
#define MAX_ADMIN_RETRY_COUNT 10

/* Максимальное количество попыток доступа Пользователя */
#define MAX_USER_RETRY_COUNT 10

/************************************************************************
 * Вспомогательные переменные                                           *
 ************************************************************************/
static CK_BBOOL attributeTrue = CK_TRUE;
static CK_BBOOL attributeFalse = CK_FALSE;

/* Тип сертификата */
static CK_CERTIFICATE_TYPE certificateType = CKC_X_509;

/* Категории сертификата */
static CK_ULONG unspecifiedCertificate = 0;
static CK_ULONG tokenUserCertificate = 1;
static CK_ULONG authorityCertificate = 2;
static CK_ULONG otherEntityCertificate = 3;

/* Длина модуля ключа RSA в битах */
static CK_ULONG rsaModulusBits = 1024;

/* Набор параметров КриптоПро A алгоритма ГОСТ 28147-89 */
static CK_BYTE parametersGost28147[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 };

/* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2001 */
static CK_BYTE parametersGostR3410_2001[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 };

/* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2012(256) */
static CK_BYTE parametersGostR3410_2012_256[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 };

/* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2012(512) */
static CK_BYTE parametersGostR3410_2012_512[] = { 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02,
0x01, 0x02, 0x01 };

/* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-1994 */
static CK_BYTE parametersGostR3411_1994[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 };

/* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(256) */
static CK_BYTE parametersGostR3411_2012_256[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01,
0x02, 0x02 };

/* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-2012(512) */
static CK_BYTE parametersGostR3411_2012_512[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01,
0x02, 0x03 };

/* Параметры для инициализации: разрешается использовать объекты синхронизации операционной системы */
static CK_C_INITIALIZE_ARGS initArgs = { NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR,
CKF_OS_LOCKING_OK, NULL_PTR };

/* Набор параметров для EC */
static CK_BYTE secp256k1Oid[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A };

/* Даты начала и окончания срока действия */
static CK_DATE startDate = { { '2', '0', '2', '0' }, { '1', '2' }, { '2', '5' } };
static CK_DATE endDate = { { '2', '0', '3', '0' }, { '1', '2' }, { '2', '5' } };

/************************************************************************
 * PIN-коды Рутокен                                                     *
 ************************************************************************/
/* DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR USER_PIN[] = { "12345678" };

#define USER_PIN_LEN (sizeof(USER_PIN) - 1)

/* Новый DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR NEW_USER_PIN[] = { "55555555" };

#define NEW_USER_PIN_LEN (sizeof(NEW_USER_PIN) - 1)

/* Новый DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR ALPHABETIC_USER_PIN[] = { "abcdefgh" };

#define ALPHABETIC_USER_PIN_LEN (sizeof(ALPHABETIC_USER_PIN) - 1)

/* Неправильный DEMO PIN-код Пользователя Рутокен */
static CK_UTF8CHAR WRONG_USER_PIN[] = { "00000000" };

#define WRONG_USER_PIN_LEN (sizeof(WRONG_USER_PIN) - 1)

/* DEMO PIN-код Администратора Рутокен */
static CK_UTF8CHAR SO_PIN[] = { "87654321" };

#define SO_PIN_LEN (sizeof(SO_PIN) - 1)

/* DEMO локальный PIN-код Рутокен */
static CK_UTF8CHAR LOCAL_PIN[] = { "1234567890" };

#define LOCAL_PIN_LEN (sizeof(LOCAL_PIN) - 1)

/************************************************************************
 * Описание типов пользователей                                         *
 ************************************************************************/
static CK_USER_TYPE userTypeSO = CKU_SO;
static CK_USER_TYPE userTypeUser = CKU_USER;

/************************************************************************
 * Описание типов объектов                                              *
 ************************************************************************/
static CK_OBJECT_CLASS publicKeyObject = CKO_PUBLIC_KEY;
static CK_OBJECT_CLASS privateKeyObject = CKO_PRIVATE_KEY;
static CK_OBJECT_CLASS secretKeyObject = CKO_SECRET_KEY;
static CK_OBJECT_CLASS certificateObject = CKO_CERTIFICATE;
static CK_OBJECT_CLASS dataObject = CKO_DATA;
static CK_OBJECT_CLASS hardwareFeatureObject = CKO_HW_FEATURE;

/************************************************************************
 * Описание типов ключей                                                *
 ************************************************************************/
static CK_KEY_TYPE keyTypeGeneric = CKK_GENERIC_SECRET;
static CK_KEY_TYPE keyTypeRsa = CKK_RSA;
static CK_KEY_TYPE keyTypeEcdsa = CKK_EC;
static CK_KEY_TYPE keyTypeGost28147 = CKK_GOST28147;
static CK_KEY_TYPE keyTypeGostR3410_2001 = CKK_GOSTR3410;
static CK_KEY_TYPE keyTypeGostR3410_2012_256 = CKK_GOSTR3410;
static CK_KEY_TYPE keyTypeGostR3410_2012_512 = CKK_GOSTR3410_512;
static CK_KEY_TYPE keyTypeKuznechik = CKK_KUZNECHIK;
static CK_KEY_TYPE keyTypeMagma = CKK_MAGMA;
static CK_KEY_TYPE keyTypeKuznechikTwin = CKK_KUZNECHIK_TWIN_KEY;
static CK_KEY_TYPE keyTypeMagmaTwin = CKK_MAGMA_TWIN_KEY;

/************************************************************************
 * Описание типов HW фич                                                *
 ************************************************************************/
static CK_HW_FEATURE_TYPE hardwareFeatureTokenInfo = CKH_VENDOR_TOKEN_INFO;
static CK_HW_FEATURE_TYPE hardwareFeaturePinPolicy = CKH_VENDOR_PIN_POLICY;

/************************************************************************
 * Описание меток объектов                                              *
 ************************************************************************/
/* DEMO-метка открытого ключа RSA */
static CK_UTF8CHAR publicKeyLabelRsa[] = { "Sample RSA Public Key (Aktiv Co.)" };

/* DEMO-метка закрытого ключа RSA */
static CK_UTF8CHAR privateKeyLabelRsa[] = { "Sample RSA Private Key (Aktiv Co.)" };

/* DEMO ID пары ключей RSA */
static CK_BYTE keyPairIdRsa[] = { "RSA sample key pair ID (Aktiv Co.)" };

/* DEMO-метка открытого ключа ECDSA */
static CK_UTF8CHAR publicKeyLabelEcdsa[] = { "Sample ECDSA Public Key (Aktiv Co.)" };

/* DEMO-метка закрытого ключа ECDSA */
static CK_UTF8CHAR privateKeyLabelEcdsa[] = { "Sample ECDSA Private Key (Aktiv Co.)" };

/* DEMO ID пары ключей ECDSA */
static CK_BYTE keyPairIdEcdsa[] = { "ECDSA sample key pair ID (Aktiv Co.)" };

/* DEMO-метка открытого ключа #1 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR publicKeyLabelGost2001_1[] = {
"Sample GOST R 34.10-2001 Public Key 1 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #1 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR privateKeyLabelGost2001_1[] = {
"Sample GOST R 34.10-2001 Private Key 1 (Aktiv Co.)"
};

/* DEMO ID пары ключей #1 ГОСТ Р 34.10-2001 */
static CK_BYTE keyPairIdGost2001_1[] = { "GOST R 34.10-2001 sample key pair 1 ID (Aktiv Co.)" };

/* DEMO-метка открытого ключа #2 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR publicKeyLabelGost2001_2[] = {
"Sample GOST R 34.10-2001 Public Key 2 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #2 ГОСТ Р 34.10-2001 */
static CK_UTF8CHAR privateKeyLabelGost2001_2[] = {
"Sample GOST R 34.10-2001 Private Key 2 (Aktiv Co.)"
};

/* DEMO ID пары ключей #2 ГОСТ Р 34.10-2001 */
static CK_BYTE keyPairIdGost2001_2[] = {
"GOST R 34.10-2001 sample key pair 2 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #1 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR publicKeyLabelGost2012_256_1[] = {
"Sample GOST R 34.10-2012 (256 bits) Public Key 1 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #1 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR privateKeyLabelGost2012_256_1[] = {
    "Sample GOST R 34.10-2012 (256 bits) Private Key 1 (Aktiv Co.)"
};

/* DEMO ID пары ключей #1 ГОСТ Р 34.10-2012(256) */
static CK_BYTE keyPairIdGost2012_256_1[] = {
"GOST R 34.10-2012 (256 bits) sample key pair 1 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #2 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR publicKeyLabelGost2012_256_2[] = {
"Sample GOST R 34.10-2012 (256 bits) Public Key 2 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #2 ГОСТ Р 34.10-2012(256) */
static CK_UTF8CHAR privateKeyLabelGost2012_256_2[] = {
    "Sample GOST R 34.10-2012 (256 bits) Private Key 2 (Aktiv Co.)"
};

/* DEMO ID пары ключей #2 ГОСТ Р 34.10-2012(256) */
static CK_BYTE keyPairIdGost2012_256_2[] = {
"GOST R 34.10-2012 (256 bits) sample key pair 2 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #1 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR publicKeyLabelGost2012_512_1[] = {
"Sample GOST R 34.10-2012 (512 bits) Public Key 1 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #1 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR privateKeyLabelGost2012_512_1[] = {
    "Sample GOST R 34.10-2012 (512 bits) Private Key 1 (Aktiv Co.)"
};

/* DEMO ID пары ключей #1 ГОСТ Р 34.10-2012(512) */
static CK_BYTE keyPairIdGost2012_512_1[] = {
"GOST R 34.10-2012 (512 bits) sample key pair 1 ID (Aktiv Co.)"
};

/* DEMO-метка открытого ключа #2 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR publicKeyLabelGost2012_512_2[] = {
"Sample GOST R 34.10-2012 (512 bits) Public Key 2 (Aktiv Co.)"
};

/* DEMO-метка закрытого ключа #2 ГОСТ Р 34.10-2012(512) */
static CK_UTF8CHAR privateKeyLabelGost2012_512_2[] = {
    "Sample GOST R 34.10-2012 (512 bits) Private Key 2 (Aktiv Co.)"
};

/* DEMO ID пары ключей #2 ГОСТ Р 34.10-2012(512) */
static CK_BYTE keyPairIdGost2012_512_2[] = {
"GOST R 34.10-2012 (512 bits) sample key pair 2 ID (Aktiv Co.)"
};

/* DEMO-метка симметричного ключа ГОСТ 28147-89 */
static CK_UTF8CHAR secretKeyLabel[] = { "Sample GOST 28147-89 Secret Key (Aktiv Co.)" };

/* DEMO-метка симметричного ключа ГОСТ 34.12-2018 с длиной блока 128 бит (Кузнечик) */
static CK_UTF8CHAR secretKeyKuznechikLabel[] = { "Sample Kuznechik Secret Key (Aktiv Co.)" };

/* DEMO-метка симметричного ключа ГОСТ 34.12-2018 с длиной блока 64 бита (Магма) */
static CK_UTF8CHAR secretKeyMagmaLabel[] = { "Sample Magma Secret Key (Aktiv Co.)" };

/* DEMO ID симметричного ключа ГОСТ 28147-89 */
static CK_BYTE secretKeyId[] = { "GOST 28147-89 Secret Key ID (Aktiv Co.)" };

/* DEMO ID симметричного ключа ГОСТ 34.12-2018 с длиной блока 128 бит (Кузнечик) */
static CK_BYTE secretKeyKuznechikId[] = { "Kuznechik Secret Key ID (Aktiv Co.)" };

/* DEMO ID симметричного ключа ГОСТ 34.12-2018 с длиной блока 64 бита (Магма) */
static CK_BYTE secretKeyMagmaId[] = { "Magma Secret Key ID (Aktiv Co.)" };

/* DEMO-метка выработанного ключа обмена ГОСТ 28147-89 */
static CK_UTF8CHAR derivedKeyLabel[] = { "Derived GOST 28147-89 key" };

/* DEMO-метка выработанного ключа обмена */
static CK_UTF8CHAR genericSecretKeyLabel[] = { "Derived generic secret key" };

/* DEMO-метка для сессионного ключа */
static CK_UTF8CHAR sessionKeyLabel[] = { "GOST 28147-89 key to wrap" };

/* DEMO-метка для демаскированного ключа */
static CK_UTF8CHAR unwrappedKeyLabel[] = { "Unwrapped GOST 28147-89 key" };

/* DEMO-метка для объекта с бинарными данными */
static CK_UTF8CHAR dataObjectLabel[] = "Sample data object label (Aktiv Co.)";

/* DEMO-метка приложения для объекта с бинарными данными */
static CK_UTF8CHAR applicationLabel[] = "Sample application label (Aktiv Co.)";

/************************************************************************
 * Описание меток токена                                                *
 ************************************************************************/
/* DEMO метка Rutoken ("длинная") */
static CK_CHAR tokenLongLabel[] = { "!!!Sample Rutoken Long-long-long-long-long label!!!" };

/* DEMO метка Rutoken ("обычная") */
static CK_CHAR tokenStdLabel[] = { "!!!Sample Rutoken label!!!" };

/* DEMO метка Rutoken */
static CK_UTF8CHAR tokenLabel[] = {
'M', 'y', ' ', 'R', 'u', 't', 'o', 'k', 'e', 'n', ' ', ' ', ' ', ' ', ' ', ' ',
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
};

/*************************************************************************
 * Механизмы PKCS#11                                                     *
 *************************************************************************/
/* Механизм генерации ключевой пары RSA */
static CK_MECHANISM rsaKeyPairGenMech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм шифрования/расшифрования по алгоритму RSA */
static CK_MECHANISM rsaEncDecMech = { CKM_RSA_PKCS, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму RSA */
static CK_MECHANISM rsaSigVerMech = { CKM_RSA_PKCS, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму RSA со встроенным хешированием по алгоритму SHA-256 */
static CK_MECHANISM rsaSigVerMech_WithSha256 = { CKM_SHA256_RSA_PKCS, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ECDSA */
static CK_MECHANISM ecdsaKeyPairGenMech = { CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ECDSA */
static CK_MECHANISM ecdsaSigVerMech = { CKM_ECDSA, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ГОСТ Р 34.10-2001 */
static CK_MECHANISM gostR3410_2001KeyPairGenMech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ГОСТ Р 34.10-2012(256) */
static CK_MECHANISM gostR3410_2012_256KeyPairGenMech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм генерации ключевой пары ГОСТ Р 34.10-2012(512) */
static CK_MECHANISM gostR3410_2012_512KeyPairGenMech = { CKM_GOSTR3410_512_KEY_PAIR_GEN, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */
static CK_MECHANISM gostR3410_2001SigVerMech = { CKM_GOSTR3410, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(256) */
static CK_MECHANISM gostR3410_2012_256SigVerMech = { CKM_GOSTR3410, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(512) */
static CK_MECHANISM gostR3410_2012_512SigVerMech = { CKM_GOSTR3410_512, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 со встроенным
 * хешированием по алгоритму ГОСТ Р 34.11-94 */
static CK_MECHANISM gostR3410_2001SigVerMech_WithHash = { CKM_GOSTR3410_WITH_GOSTR3411, NULL_PTR, 0 };

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(256) со встроенным
 * хешированием по алгоритму ГОСТ Р 34.11-2012(256) */
static CK_MECHANISM gostR3410_2012_256SigVerMech_WithHash = {
CKM_GOSTR3410_WITH_GOSTR3411_12_256, NULL_PTR, 0
};

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(512) со встроенным
 * хешированием по алгоритму ГОСТ Р 34.11-2012(512) */
static CK_MECHANISM gostR3410_2012_512SigVerMech_WithHash = {
CKM_GOSTR3410_WITH_GOSTR3411_12_512, NULL_PTR, 0
};

/* Механизмы генерации симметричного ключа по алгоритму ГОСТ 34.12 */
static CK_MECHANISM kuznechikKeyGenMech = { CKM_KUZNECHIK_KEY_GEN, NULL_PTR, 0 };
static CK_MECHANISM magmaKeyGenMech = { CKM_MAGMA_KEY_GEN, NULL_PTR, 0 };

/* Механизмы шифрования/расшифрования по алгоритму ГОСТ 34.12 */
static CK_MECHANISM kuznechikEncDecEcbMech = { CKM_KUZNECHIK_ECB, NULL_PTR, 0 };
static CK_BYTE kuznechikEncMechParams[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static CK_MECHANISM kuznechikEncDecMech = { CKM_KUZNECHIK_CTR_ACPKM, &kuznechikEncMechParams,
                                            sizeof(kuznechikEncMechParams) };
static CK_MECHANISM magmaEncDecEcbMech = { CKM_MAGMA_ECB, NULL_PTR, 0 };
static CK_BYTE magmaEncMechParams[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static CK_MECHANISM magmaEncDecMech = {
CKM_MAGMA_CTR_ACPKM, &magmaEncMechParams, sizeof(magmaEncMechParams)
};

/* Механизм выработки имитовставки ГОСТ 34.12 */
static CK_MECHANISM kuznechikMacMech = { CKM_KUZNECHIK_MAC, NULL_PTR, 0 };
static CK_MECHANISM magmaMacMech = { CKM_MAGMA_MAC, NULL_PTR, 0 };

/* Механизм генерации симметричного ключа по алгоритму ГОСТ 28147-89 */
static CK_MECHANISM gost28147KeyGenMech = { CKM_GOST28147_KEY_GEN, NULL_PTR, 0 };

/* Механизм шифрования/расшифрования по алгоритму ГОСТ 28147-89 */
static CK_MECHANISM gost28147EncDecEcbMech = { CKM_GOST28147_ECB, NULL_PTR, 0 };
static CK_MECHANISM gost28147EncDecMech = { CKM_GOST28147, NULL_PTR, 0 };

/* Механизм выработки имитовставки ГОСТ 28147-89 */
static CK_MECHANISM gost28147MacMech = { CKM_GOST28147_MAC, NULL_PTR, 0 };

/* Механизм выработки HMAC по алгоритму ГОСТ Р 34.11-94 */
static CK_MECHANISM gostR3411HmacMech = { CKM_GOSTR3411_HMAC, NULL_PTR, 0 };

/* Механизм выработки HMAC по алгоритму ГОСТ Р 34.11-2012(256) */
static CK_MECHANISM gostR3411_2012_256HmacMech = { CKM_GOSTR3411_12_256_HMAC, NULL_PTR, 0 };

/* Механизм выработки HMAC по алгоритму ГОСТ Р 34.11-2012(512) */
static CK_MECHANISM gostR3411_2012_512HmacMech = { CKM_GOSTR3411_12_512_HMAC, NULL_PTR, 0 };

/* Механизм хеширования SHA-256 */
static CK_MECHANISM sha256Mech = { CKM_SHA256, NULL_PTR, 0 };

/* Механизм хеширования ГОСТ Р 34.11-94 */
static CK_MECHANISM gostR3411_1994HashMech = { CKM_GOSTR3411, NULL_PTR, 0 };

/* Механизм хеширования ГОСТ Р 34.11-2012(256) */
static CK_MECHANISM gostR3411_2012_256HashMech = { CKM_GOSTR3411_12_256, NULL_PTR, 0 };

/* Механизм хеширования ГОСТ Р 34.11-2012(512) */
static CK_MECHANISM gostR3411_2012_512HashMech = { CKM_GOSTR3411_12_512, NULL_PTR, 0 };

/* Механизм для маскирования/демаскирования ключа */
static CK_MECHANISM gost28147WrapMech = { CKM_GOST28147_KEY_WRAP, NULL_PTR, 0 };

/* Механизм выработки ключа обмена по алгоритму VKO GOST R 34.10-2001 */
static CK_MECHANISM gostR3410_2001DerivationMech = { CKM_GOSTR3410_DERIVE, NULL_PTR, 0 };

/* Механизм выработки ключа обмена по алгоритму VKO GOST R 34.10-2012 */
static CK_MECHANISM gostR3410_12DerivationMech = { CKM_GOSTR3410_12_DERIVE, NULL_PTR, 0 };

/* Механизм выработки ключа обмена по алгоритму KEG для TLS 1.2 */
static CK_MECHANISM gostKegDerivationMech = { CKM_GOST_KEG, NULL_PTR, 0 };

/* Параметры для выработки ключа обмена */
static CK_GOSTR3410_DERIVE_PARAMS deriveParameters = { CKD_CPDIVERSIFY_KDF, NULL_PTR, 0, NULL_PTR, 0 };

/**************************************************************************
 * Механизмы PKCS#11 с программной реализацией.                           *
 * Использование данных механизмов предполагает выполнение                *
 * криптографической операции на центральном процессоре, что может        *
 * положительно повлиять на скорость выполнения операции, но отрицательно *
 * на обеспечение безопасности                                            *
 **************************************************************************/
/* Механизм программного хеширования ГОСТ Р 34.11-94
   static CK_MECHANISM gostR3411_1994HashMech = { CKM_GOSTR3411, parametersGostR3411_1994,
   sizeof(parametersGostR3411_1994) }; */

/* Механизм программного хеширования ГОСТ Р 34.11-2012(256)
   static CK_MECHANISM gostR3411_2012_256HashMech = { CKM_GOSTR3411_12_256, parametersGostR3411_2012_256,
   sizeof(parametersGostR3411_2012_256) }; */

/* Механизм программного хеширования ГОСТ Р 34.11-2012(512)
   static CK_MECHANISM gostR3411_2012_512HashMech = { CKM_GOSTR3411_12_512, parametersGostR3411_2012_512,
   sizeof(parametersGostR3411_2012_512) }; */

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 со встроенным
   программным хешированием по алгоритму ГОСТ Р 34.11-94
   static CK_MECHANISM gostR3410_2001SigVerMech_WithHash = { CKM_GOSTR3410_WITH_GOSTR3411,
        parametersGostR3411_1994, sizeof(parametersGostR3411_1994) }; */

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(256) со встроенным
   программным хешированием по алгоритму ГОСТ Р 34.11-2012(256)
   static CK_MECHANISM gostR3410_2012_256SigVerMech_WithHash = {
        CKM_GOSTR3410_WITH_GOSTR3411_12_256, parametersGostR3411_2012_256,
sizeof(parametersGostR3411_2012_256)
}; */

/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2012(512) со встроенным
   программным хешированием по алгоритму ГОСТ Р 34.11-2012(512)
   static CK_MECHANISM gostR3410_2012_512SigVerMech_WithHash = {
        CKM_GOSTR3410_WITH_GOSTR3411_12_512, parametersGostR3411_2012_512,
sizeof(parametersGostR3411_2012_512) };
*/

/*************************************************************************
 * Запрос на получение сертификата                                       *
 *************************************************************************/
/*************************************************************************
 * Список полей DN (Distinguished Name)                                  *
 *************************************************************************/
CK_CHAR_PTR dn[] = {
    (CK_CHAR_PTR) "CN",                // Тип поля CN (Common Name)
    (CK_CHAR_PTR) "UTF8String:Иванов", // Значение
    (CK_CHAR_PTR) "C",                 // C (Country)
    (CK_CHAR_PTR) "RU",
    (CK_CHAR_PTR) "2.5.4.5", // SN (Serial Number)
    (CK_CHAR_PTR) "12312312312",
    (CK_CHAR_PTR) "1.2.840.113549.1.9.1", // E (E-mail)
    (CK_CHAR_PTR) "ivanov@mail.ru",
    (CK_CHAR_PTR) "ST", // ST (State or province)
    (CK_CHAR_PTR) "UTF8String:Москва",
    (CK_CHAR_PTR) "O", // O (Organization)
    (CK_CHAR_PTR) "CompanyName",
    (CK_CHAR_PTR) "OU", // OU (Organizational Unit)
    (CK_CHAR_PTR) "Devel",
    (CK_CHAR_PTR) "L", // L (Locality)
    (CK_CHAR_PTR) "Moscow",
};

/*************************************************************************
 * Список дополнительных полей                                           *
 *************************************************************************/
CK_CHAR_PTR exts[] = {
    (CK_CHAR_PTR) "keyUsage", // Использование ключа
    (CK_CHAR_PTR) "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment",
    (CK_CHAR_PTR) "extendedKeyUsage", // Дополнительное использование
    (CK_CHAR_PTR) "1.2.643.2.2.34.6,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.4",
    (CK_CHAR_PTR) "2.5.29.14", // Идентификатор ключа субъекта (SKI)
    (CK_CHAR_PTR) "hash", // Если задать значение hash - идентификатор ключа субъекта будет
                  // сформирован библиотекой автоматически.
// Также идентификатор ключа субъекта можно задать вручную
                  // (CK_CHAR_PTR)"ASN1:FORMAT:HEX,OCTETSTRING:FE117B93CEC6B5065E1613E155D3A9CA597C0F81",
    (CK_CHAR_PTR) "2.5.29.17", // Дополнительное имя (пример с кодированием в виде DER)
    (CK_CHAR_PTR) "DER:30:0F:81:0D:65:78:61:6d:70:6c:65:40:79:61:2E:72:75",
    (CK_CHAR_PTR) "2.5.29.32", // Политики сертификата (кодирование в виде DER с пометкой "critical")
    (CK_CHAR_PTR) "critical,DER:30:0A:30:08:06:06:2A:85:03:64:71:01",
    (CK_CHAR_PTR) "1.2.643.100.111", // Средства электронной подписи владельца
    (CK_CHAR_PTR) "ASN1:UTF8String:СКЗИ \\\"Рутокен ЭЦП 2.0\\\"",
};

/*************************************************************************
 * Функция преобразования ошибки PKCS#11 к строке                        *
 *************************************************************************/
static const char* rvToStr(CK_RV rv) {
    switch (rv) {
    case CKR_OK:
        return "CKR_OK";
    case CKR_CANCEL:
        return "CKR_CANCEL";
    case CKR_HOST_MEMORY:
        return "CKR_HOST_MEMORY";
    case CKR_SLOT_ID_INVALID:
        return "CKR_SLOT_ID_INVALID";
    case CKR_GENERAL_ERROR:
        return "CKR_GENERAL_ERROR";
    case CKR_FUNCTION_FAILED:
        return "CKR_FUNCTION_FAILED";
    case CKR_ARGUMENTS_BAD:
        return "CKR_ARGUMENTS_BAD";
    case CKR_NO_EVENT:
        return "CKR_NO_EVENT";
    case CKR_NEED_TO_CREATE_THREADS:
        return "CKR_NEED_TO_CREATE_THREADS";
    case CKR_CANT_LOCK:
        return "CKR_CANT_LOCK";
    case CKR_ATTRIBUTE_READ_ONLY:
        return "CKR_ATTRIBUTE_READ_ONLY";
    case CKR_ATTRIBUTE_SENSITIVE:
        return "CKR_ATTRIBUTE_SENSITIVE";
    case CKR_ATTRIBUTE_TYPE_INVALID:
        return "CKR_ATTRIBUTE_TYPE_INVALID";
    case CKR_ATTRIBUTE_VALUE_INVALID:
        return "CKR_ATTRIBUTE_VALUE_INVALID";
    case CKR_DATA_INVALID:
        return "CKR_DATA_INVALID";
    case CKR_DATA_LEN_RANGE:
        return "CKR_DATA_LEN_RANGE";
    case CKR_DEVICE_ERROR:
        return "CKR_DEVICE_ERROR";
    case CKR_DEVICE_MEMORY:
        return "CKR_DEVICE_MEMORY";
    case CKR_DEVICE_REMOVED:
        return "CKR_DEVICE_REMOVED";
    case CKR_ENCRYPTED_DATA_INVALID:
        return "CKR_ENCRYPTED_DATA_INVALID";
    case CKR_ENCRYPTED_DATA_LEN_RANGE:
        return "CKR_ENCRYPTED_DATA_LEN_RANGE";
    case CKR_FUNCTION_CANCELED:
        return "CKR_FUNCTION_CANCELED";
    case CKR_FUNCTION_NOT_PARALLEL:
        return "CKR_FUNCTION_NOT_PARALLEL";
    case CKR_FUNCTION_NOT_SUPPORTED:
        return "CKR_FUNCTION_NOT_SUPPORTED";
    case CKR_KEY_HANDLE_INVALID:
        return "CKR_KEY_HANDLE_INVALID";
    case CKR_KEY_SIZE_RANGE:
        return "CKR_KEY_SIZE_RANGE";
    case CKR_KEY_TYPE_INCONSISTENT:
        return "CKR_KEY_TYPE_INCONSISTENT";
    case CKR_KEY_NOT_NEEDED:
        return "CKR_KEY_NOT_NEEDED";
    case CKR_KEY_CHANGED:
        return "CKR_KEY_CHANGED";
    case CKR_KEY_NEEDED:
        return "CKR_KEY_NEEDED";
    case CKR_KEY_INDIGESTIBLE:
        return "CKR_KEY_INDIGESTIBLE";
    case CKR_KEY_FUNCTION_NOT_PERMITTED:
        return "CKR_KEY_FUNCTION_NOT_PERMITTED";
    case CKR_KEY_NOT_WRAPPABLE:
        return "CKR_KEY_NOT_WRAPPABLE";
    case CKR_KEY_UNEXTRACTABLE:
        return "CKR_KEY_UNEXTRACTABLE";
    case CKR_MECHANISM_INVALID:
        return "CKR_MECHANISM_INVALID";
    case CKR_MECHANISM_PARAM_INVALID:
        return "CKR_MECHANISM_PARAM_INVALID";
    case CKR_OBJECT_HANDLE_INVALID:
        return "CKR_OBJECT_HANDLE_INVALID";
    case CKR_OPERATION_ACTIVE:
        return "CKR_OPERATION_ACTIVE";
    case CKR_OPERATION_NOT_INITIALIZED:
        return "CKR_OPERATION_NOT_INITIALIZED";
    case CKR_PIN_INCORRECT:
        return "CKR_PIN_INCORRECT";
    case CKR_PIN_INVALID:
        return "CKR_PIN_INVALID";
    case CKR_PIN_LEN_RANGE:
        return "CKR_PIN_LEN_RANGE";
    case CKR_PIN_EXPIRED:
        return "CKR_PIN_EXPIRED";
    case CKR_PIN_LOCKED:
        return "CKR_PIN_LOCKED";
    case CKR_SESSION_CLOSED:
        return "CKR_SESSION_CLOSED";
    case CKR_SESSION_COUNT:
        return "CKR_SESSION_COUNT";
    case CKR_SESSION_HANDLE_INVALID:
        return "CKR_SESSION_HANDLE_INVALID";
    case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
        return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
    case CKR_SESSION_READ_ONLY:
        return "CKR_SESSION_READ_ONLY";
    case CKR_SESSION_EXISTS:
        return "CKR_SESSION_EXISTS";
    case CKR_SESSION_READ_ONLY_EXISTS:
        return "CKR_SESSION_READ_ONLY_EXISTS";
    case CKR_SESSION_READ_WRITE_SO_EXISTS:
        return "CKR_SESSION_READ_WRITE_SO_EXISTS";
    case CKR_SIGNATURE_INVALID:
        return "CKR_SIGNATURE_INVALID";
    case CKR_SIGNATURE_LEN_RANGE:
        return "CKR_SIGNATURE_LEN_RANGE";
    case CKR_TEMPLATE_INCOMPLETE:
        return "CKR_TEMPLATE_INCOMPLETE";
    case CKR_TEMPLATE_INCONSISTENT:
        return "CKR_TEMPLATE_INCONSISTENT";
    case CKR_TOKEN_NOT_PRESENT:
        return "CKR_TOKEN_NOT_PRESENT";
    case CKR_TOKEN_NOT_RECOGNIZED:
        return "CKR_TOKEN_NOT_RECOGNIZED";
    case CKR_TOKEN_WRITE_PROTECTED:
        return "CKR_TOKEN_WRITE_PROTECTED";
    case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
        return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
    case CKR_UNWRAPPING_KEY_SIZE_RANGE:
        return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
    case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
        return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
    case CKR_USER_ALREADY_LOGGED_IN:
        return "CKR_USER_ALREADY_LOGGED_IN";
    case CKR_USER_NOT_LOGGED_IN:
        return "CKR_USER_NOT_LOGGED_IN";
    case CKR_USER_PIN_NOT_INITIALIZED:
        return "CKR_USER_PIN_NOT_INITIALIZED";
    case CKR_USER_TYPE_INVALID:
        return "CKR_USER_TYPE_INVALID";
    case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
        return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
    case CKR_USER_TOO_MANY_TYPES:
        return "CKR_USER_TOO_MANY_TYPES";
    case CKR_WRAPPED_KEY_INVALID:
        return "CKR_WRAPPED_KEY_INVALID";
    case CKR_WRAPPED_KEY_LEN_RANGE:
        return "CKR_WRAPPED_KEY_LEN_RANGE";
    case CKR_WRAPPING_KEY_HANDLE_INVALID:
        return "CKR_WRAPPING_KEY_HANDLE_INVALID";
    case CKR_WRAPPING_KEY_SIZE_RANGE:
        return "CKR_WRAPPING_KEY_SIZE_RANGE";
    case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
        return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
    case CKR_RANDOM_SEED_NOT_SUPPORTED:
        return "CKR_RANDOM_SEED_NOT_SUPPORTED";
    case CKR_RANDOM_NO_RNG:
        return "CKR_RANDOM_NO_RNG";
    case CKR_DOMAIN_PARAMS_INVALID:
        return "CKR_DOMAIN_PARAMS_INVALID";
    case CKR_BUFFER_TOO_SMALL:
        return "CKR_BUFFER_TOO_SMALL";
    case CKR_SAVED_STATE_INVALID:
        return "CKR_SAVED_STATE_INVALID";
    case CKR_INFORMATION_SENSITIVE:
        return "CKR_INFORMATION_SENSITIVE";
    case CKR_STATE_UNSAVEABLE:
        return "CKR_STATE_UNSAVEABLE";
    case CKR_CRYPTOKI_NOT_INITIALIZED:
        return "CKR_CRYPTOKI_NOT_INITIALIZED";
    case CKR_CRYPTOKI_ALREADY_INITIALIZED:
        return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
    case CKR_MUTEX_BAD:
        return "CKR_MUTEX_BAD";
    case CKR_MUTEX_NOT_LOCKED:
        return "CKR_MUTEX_NOT_LOCKED";
    case CKR_NEW_PIN_MODE:
        return "CKR_NEW_PIN_MODE";
    case CKR_NEXT_OTP:
        return "CKR_NEXT_OTP";
    case CKR_FUNCTION_REJECTED:
        return "CKR_FUNCTION_REJECTED";
    case CKR_CORRUPTED_MAPFILE:
        return "CKR_CORRUPTED_MAPFILE";
    case CKR_WRONG_VERSION_FIELD:
        return "CKR_WRONG_VERSION_FIELD";
    case CKR_WRONG_PKCS1_ENCODING:
        return "CKR_WRONG_PKCS1_ENCODING";
    case CKR_RTPKCS11_DATA_CORRUPTED:
        return "CKR_RTPKCS11_DATA_CORRUPTED";
    case CKR_RTPKCS11_RSF_DATA_CORRUPTED:
        return "CKR_RTPKCS11_RSF_DATA_CORRUPTED";
    case CKR_SM_PASSWORD_INVALID:
        return "CKR_SM_PASSWORD_INVALID";
    case CKR_LICENSE_READ_ONLY:
        return "CKR_LICENSE_READ_ONLY";
    default:
        return "Unknown error";
    }
}

/*************************************************************************
 * Макросы проверки ошибки. Если произошла ошибка, то выводится          *
 * сообщение и осуществляется переход на заданную метку                  *
 *************************************************************************/
#define CHECK_AND_LOG_ONLY_ERROR(expression, errMsg, label) \
    do {                                                    \
        if (!(expression)) {                                \
            printf(" -> Failed\n%s\n", errMsg);             \
            goto label;                                     \
        }                                                   \
    } while (0)

#define CHECK_AND_LOG(msg, expression, errMsg, label) \
    do {                                              \
        printf("%s", msg);                            \
        if (!(expression)) {                          \
            printf(" -> Failed\n%s\n", errMsg);       \
            goto label;                               \
        } else {                                      \
            printf(" -> OK\n");                       \
        }                                             \
    } while (0)

#define CHECK(msg, expression, label) CHECK_AND_LOG(msg, expression, "", label)

/*************************************************************************
 * Макросы проверки ошибки при освобождении ресурсов.                    *
 * Если произошла ошибка, то выводится сообщение                         *
 * и выставляется значение переменной errorCode                          *
 *************************************************************************/
#define CHECK_RELEASE_AND_LOG(msg, expression, errMsg, errorCode) \
    do {                                                          \
        printf("%s", msg);                                        \
        if (!(expression)) {                                      \
            printf(" -> Failed\n%s\n", errMsg);                   \
            errorCode = 1;                                        \
        } else {                                                  \
            printf(" -> OK\n");                                   \
        }                                                         \
    } while (0)

#define CHECK_RELEASE(msg, expression, errorCode) CHECK_RELEASE_AND_LOG(msg, expression, "", errorCode)

/*************************************************************************
 * Макросы проверки ошибки. Если произошла ошибка, то выводится          *
 * сообщение и выполняется оператор проверочного утверждения             *
 *************************************************************************/
#define ASSERT_AND_LOG_AND_ERRMSG(msg, expression, errMsg) \
    do {                                                   \
        printf("%s", msg);                                 \
        if (!(expression)) {                               \
            printf("%s -> Failed\n%s\n", msg, errMsg);     \
            abort();                                       \
        } else {                                           \
            printf(" -> OK\n");                            \
        }                                                  \
    } while (0)

#define ASSERT_AND_LOG(msg, expression) ASSERT_AND_LOG_AND_ERRMSG(msg, expression, "")

#define ASSERT(msg, expression)            \
    do {                                   \
        if (!(expression)) {               \
            printf("%s -> Failed\n", msg); \
            abort();                       \
        }                                  \
    } while (0)

/*************************************************************************
 * Функция поиска объектов по заданному шаблону                          *
 *************************************************************************/
static int findObjects(CK_FUNCTION_LIST_PTR functionList, // Указатель на список функций PKCS#11
                       CK_SESSION_HANDLE session,         // Дескриптор открытой сессии
                       CK_ATTRIBUTE_PTR attributes,       // Массив с шаблоном для поиска
                       CK_ULONG attrCount,                // Количество атрибутов в массиве поиска
                       CK_OBJECT_HANDLE_PTR* objects,     // Массив для записи найденных объектов
                       CK_ULONG* objectsCount             // Количество найденных объектов
) {
    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    CK_ULONG newObjectsCount;    // Количество объектов, найденных при конкретном вызове C_FindObjects
    CK_ULONG bufferSize;         // Текущий размер буфера с объектами
    CK_OBJECT_HANDLE_PTR buffer; // Буфер, получаемый из realloc
    int errorCode = 1;           // Флаг ошибки

    /*************************************************************************
     * Инициализировать операцию поиска                                      *
     *************************************************************************/
    rv = functionList->C_FindObjectsInit(session, attributes, attrCount);
    CHECK_AND_LOG("  C_FindObjectsInit", rv == CKR_OK, rvToStr(rv), exit);

    /*************************************************************************
     * Найти все объекты, соответствующие критериям поиска                   *
     *************************************************************************/
    *objects = NULL;
    *objectsCount = 0;

    for (bufferSize = 8;; bufferSize *= 2) {
        buffer = (CK_OBJECT_HANDLE_PTR)realloc(*objects, bufferSize * sizeof(CK_OBJECT_HANDLE));
        CHECK("  Memory allocation for object handles", buffer != NULL, find_final);
        *objects = buffer;

        rv = functionList->C_FindObjects(session, *objects + *objectsCount, bufferSize - *objectsCount,
                                         &newObjectsCount);
        CHECK_AND_LOG("  C_FindObjects", rv == CKR_OK, rvToStr(rv), find_final);

        *objectsCount += newObjectsCount;

        if (*objectsCount < bufferSize) {
            break;
        }
    }

    /*************************************************************************
     * Освободить неиспользуемую память                                      *
     *************************************************************************/
    if (*objectsCount != 0) {
        buffer = (CK_OBJECT_HANDLE_PTR)realloc(*objects, *objectsCount * sizeof(CK_OBJECT_HANDLE));
        CHECK("  Memory reallocation for object handles", buffer != NULL, find_final);
        *objects = buffer;
    }

    errorCode = 0;

    /*************************************************************************
     * Деинициализировать операцию поиска                                    *
     *************************************************************************/
find_final:
    rv = functionList->C_FindObjectsFinal(session);
    CHECK_RELEASE_AND_LOG("  C_FindObjectsFinal", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под объекты                               *
     *************************************************************************/
    if (errorCode || *objectsCount == 0) {
        free(*objects);
        *objects = NULL_PTR;
    }

exit:
    return errorCode;
}

/*************************************************************************
 * Функция вывода шестнадцатеричного буфера заданной длины               *
 *************************************************************************/
static void printHexBuffer(const CK_BYTE* buffer,        // Буфер
                           const CK_ULONG length,        // Длина буфера
                           const CK_ULONG width,         // Байт в строке
                           const CK_BYTE offset,         // Смещение каждой строки
                           const CK_BYTE firstLineOffset // Смещение первой строки
) {
    unsigned int lineOffset = firstLineOffset;
    for (unsigned int i = 0; i < length; ++i) {
        if (width != 0) {
            if (i % width == 0) {
                for (unsigned int j = 0; j < lineOffset; ++j) {
                    printf(" ");
                }
            }
        }

        printf("%02X ", buffer[i]);

        if (width != 0) {
            if ((i + 1) % width == 0 || (i + 1) == length) {
                printf("\n");
            }
        } else if ((i + 1) == length) {
            printf("\n");
        }
        lineOffset = offset;
    }
}

/*************************************************************************
 * Функция вывода шестнадцатеричного буфера по 16 байт в строке          *
 *************************************************************************/
static void printHex(const CK_BYTE* buffer, // Буфер
                     const CK_ULONG length  // Длина буфера
) {
    printHexBuffer(buffer, length, 16, 3, 3);
}

/*************************************************************************
 * Функция вывода UTF-8. Выводит символы 0-127 и кириллицу. Возвращает 0 *
 * в случае успешного выполнения, иначе не 0                             *
 *************************************************************************/
static int printUTF8String(CK_BYTE* info) {
#ifdef _WIN32
    CK_ULONG sym = 0;
    UINT cp = GetConsoleOutputCP();
    BOOL set = SetConsoleOutputCP(866); // Кодировка cp-866
    if (set == FALSE) {
        return 1;
    }
    while (*info) {
        if (*info < 0x80) {
            printf("%c", *info); // Вывод однобайтовых символов
            ++info;
        } else if (*info & 0xC0) { // Вывод двухбайтовых символов
            sym = ((*info & 0x1F) << 6) + (*(info + 1) & 0x3F);
            if (sym >= 0x0410 && sym <= 0x042F) { // Прописные
                printf("%c", sym - 0x0410 + 0x80);
            } else if (sym >= 0x0430 && sym <= 0x043F) { // Строчные до 'р'
                printf("%c", sym - 0x0430 + 0xA0);
            } else if (sym >= 0x0440 && sym <= 0x044F) { // Строчные после 'р'
                printf("%c", sym - 0x0440 + 0xE0);
            } else if (sym == 0x0401) { // Ё
                printf("%c", 0xF0);
            } else if (sym == 0x0451) { // ё
                printf("%c", 0xF1);
            } else {
                printf("?"); // Все остальные двухбайтные символы
            }
            info += 2;
        } else if (*info & 0xE0) { // 3 и более байтные символы
            info += 3;
            printf("?");
        } else if (*info & 0xF0) {
            info += 4;
            printf("?");
        } else if (*info & 0xF8) {
            info += 5;
            printf("?");
        } else if (*info & 0xFC) {
            info += 6;
            printf("?");
        } else {
            ++info;
        }
    }
    set = SetConsoleOutputCP(cp);
    return !set;
#else
    printf("%s", info);
    return 0;
#endif
}

/*************************************************************************
 * Функция конвертирования 6-битного кода в печатный символ Base64       *
 *************************************************************************/
static char ConvertCodeToSymBase64(CK_BYTE code // 6-битный код
) {
    const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    if (code < 0x40) {
        return alphabet[(int)code];
    } else {
        return '?';
    }
}

/*************************************************************************
 * Функция выборки 6 бит из массива байт                                 *
 *************************************************************************/
static CK_BYTE GetNext6Bit(
CK_BYTE_PTR csr, // Указатель на начало массива
    CK_ULONG start, // Номер бита в массиве, с которого начинается группа из 6 бит
    CK_ULONG end // Номер последнего бита массива
) {
    CK_BYTE diff = start % 8;
    csr += start / 8;
    if (end - start > 8) {
        return 0x3F & (*csr << diff | *(csr + 1) >> (8 - diff)) >> 2;
    } else {
        return 0x3F & (*csr << diff >> 2);
    }
}

/*************************************************************************
 * Функция конвертирования массива байт в строку Base64                  *
 *************************************************************************/
static void ConvertToBase64String(
CK_BYTE_PTR data, // Исходные данные
    CK_ULONG size,    // Длина исходного массива
    char** result // Результирующие данные (нуль-терминированная строка)
) {
    CK_ULONG i = 0;
    char* pt;
    *result = (char*)calloc(((size_t)size + 2) / 3 * 4 + 1, sizeof(char));
    if (*result != NULL) {
        memset(*result, '=', ((size_t)size + 2) / 3 * 4);
        for (pt = *result; i < size * 8; i += 6, ++pt) {
            *pt = ConvertCodeToSymBase64(GetNext6Bit(data, i, size * 8));
        }
    }
}

/*************************************************************************
 * Функция преобразования массива байт в PEM формат                      *
 *************************************************************************/
static void GetBytesAsPem(CK_BYTE_PTR source, // Исходные данные
                          CK_ULONG size,      // Длина исходного массива
                          const char* header, // Начальный тег
                          const char* footer, // Конечный тег
                          char** result       // Результирующий запрос
) {
    size_t length;
    size_t width = 0x40;
    char* buffer;
    size_t i;

    ConvertToBase64String(source, size, &buffer);
    if (buffer == NULL) {
        *result = NULL;
        return;
    }
    length = strlen(buffer);
    *result = (char*)calloc(strlen(header)                 // Место под начальный тег
                                + length                   // Место под base64 строку
                                + strlen(footer)           // Место под конечный тег
                                + (length - 1) / width + 1 // Место под переносы строки
                                + 1,                       // Нуль-байт
                            sizeof(char));
    if (*result == NULL) {
        free(buffer);
        return;
    }
    // компоновка данных
    strcat(*result, header);
    for (i = 0; i < length; i += width) {
        strncat(*result, buffer + i, width);
        strcat(*result, "\n");
    }
    strcat(*result, footer);

    free(buffer);
}

/*************************************************************************
 * Функция получения CSR в формате PEM                                   *
 *************************************************************************/
static void GetCSRAsPEM(CK_BYTE_PTR source, // Исходные данные
                        CK_ULONG size,      // Длина исходного массива
                        char** result       // Результирующий запрос
) {
    const char* begin = "-----BEGIN NEW CERTIFICATE REQUEST-----\n"; // Начало запроса
    const char* end = "-----END NEW CERTIFICATE REQUEST-----\n";     // Конец запроса

    GetBytesAsPem(source, size, begin, end, result);
}

/*************************************************************************
 * Функция получения тела сертификата в формате PEM                      *
 *************************************************************************/
static void GetCertAsPem(CK_BYTE_PTR source, // Исходные данные
                         CK_ULONG size,      // Длина исходного массива
                         char** result       // Указатель на строку с результатом
) {
    const char* begin = "-----BEGIN CERTIFICATE-----\n"; // Начало сертификата
    const char* end = "-----END CERTIFICATE-----\n";     // Конец сертификата

    GetBytesAsPem(source, size, begin, end, result);
}

#endif // PKCS11_COMMON_H
Файл BioCommon.h. Описание типа объекта набора отпечатков пальцев 
/************************************************************************
* В каждом примере Bio*.c работа ведется с первым найденным *
* набором отпечатков. *
* Если на токене присутствует более одного набора отпечатков, *
* для работы с нужным набором следует указать *
* CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID в шаблоне поиска *
* объекта набора отпечатков *
 ************************************************************************/

#ifndef BioCommon_H
#define BioCommon_H

#include "Common.h"

/************************************************************************
 * Описание типа объекта набора отпечатков пальцев                      *
 ************************************************************************/
static CK_OBJECT_CLASS authObject = CKO_VENDOR_AUTHENTICATION_FACTOR;
static CK_VENDOR_AUTHENTICATION_FACTOR_TYPE authType = CKVAF_BIO_FP_CONVOLUTION;

/************************************************************************
 * Массив, представляющий из себя отпечаток пальца, заполненный         *
 * по ГОСТ 19794-2-2013                                                 *
 ************************************************************************/
CK_BYTE initFingerprint[] = {
    0x46, 0x4D, 0x52, 0x00, 0x30, 0x33, 0x30, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x01, 0x00,
    0x00, 0x00, 0x00, 0x86, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0xC5, 0x00, 0x01, 0x40, 0x01, 0xE0,
    0x50, 0x14, 0x40, 0x6A, 0x00, 0x48, 0xC6, 0x40, 0x59, 0x00, 0xD2, 0xE1, 0x40, 0xBA, 0x00,
    0x40, 0xA4, 0x00, 0xC4, 0x00, 0x3C, 0xB6, 0x40, 0xB0, 0x00, 0x62, 0x2E, 0x00, 0xA5, 0x00,
    0xA0, 0x72, 0x40, 0xE6, 0x00, 0xB6, 0x1E, 0x00, 0x62, 0x00, 0xB4, 0x5A, 0x00, 0xBD, 0x00,
    0x2E, 0xDA, 0x40, 0xAD, 0x00, 0x96, 0x70, 0x40, 0xCA, 0x00, 0x54, 0xAD, 0x00, 0xE6, 0x00,
    0x4C, 0x3F, 0x40, 0xF8, 0x00, 0x48, 0x36, 0x00, 0x58, 0x00, 0x4E, 0x44, 0x00, 0x7A, 0x00,
    0x42, 0x39, 0x00, 0x96, 0x00, 0x82, 0x52, 0x40, 0x9C, 0x00, 0x66, 0x42, 0x00, 0x80, 0x01,
    0x0E, 0xF6, 0x40, 0xCE, 0x00, 0x2A, 0xD2, 0x00, 0xB7, 0x01, 0x08, 0x86, 0x00, 0x00
};

/************************************************************************
 * Массивы, представляющие из себя отпечатки пальцев, заполненные       *
 * по ГОСТ 19794-2-2013. Используется для замены изначального отпечатка *
 ************************************************************************/
CK_BYTE updateFingerprint1[] = {
    0x46, 0x4D, 0x52, 0x00, 0x30, 0x33, 0x30, 0x00, 0x00, 0x00, 0x01, 0x17, 0x00, 0x01, 0x00,
    0x00, 0x00, 0x01, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0xC5, 0x00, 0x01, 0x40, 0x01, 0xE0,
    0x50, 0x2E, 0x00, 0x68, 0x00, 0xBC, 0x3B, 0x00, 0x78, 0x00, 0xEC, 0x44, 0x00, 0x74, 0x01,
    0x14, 0x52, 0x00, 0xA6, 0x00, 0x90, 0x63, 0x00, 0x9C, 0x01, 0x64, 0x70, 0x40, 0xD2, 0x00,
    0xD0, 0x51, 0x00, 0xEC, 0x00, 0x5C, 0xD8, 0x00, 0xE4, 0x00, 0xE4, 0x3F, 0x00, 0xDA, 0x01,
    0x38, 0x1A, 0x00, 0xE4, 0x01, 0x14, 0x2E, 0x01, 0x1A, 0x00, 0xC8, 0x3F, 0x01, 0x26, 0x00,
    0xB0, 0x3F, 0x00, 0xD2, 0x00, 0x4B, 0xE1, 0x01, 0x0B, 0x01, 0x31, 0x9F, 0x40, 0x8C, 0x00,
    0x72, 0xE9, 0x00, 0xB2, 0x00, 0x56, 0xE1, 0x00, 0xB4, 0x01, 0x32, 0x72, 0x40, 0xCA, 0x00,
    0xF6, 0x44, 0x01, 0x33, 0x00, 0xD4, 0x36, 0x00, 0xE4, 0x01, 0x65, 0x8D, 0x00, 0x83, 0x00,
    0x9A, 0x8B, 0x00, 0x8C, 0x00, 0xA8, 0x9A, 0x00, 0xB8, 0x00, 0x78, 0x63, 0x40, 0xB3, 0x00,
    0xBA, 0x63, 0x00, 0xEC, 0x00, 0x68, 0x5C, 0x00, 0xDF, 0x01, 0x4A, 0x8D, 0x41, 0x10, 0x00,
    0x60, 0xDF, 0x00, 0xE3, 0x01, 0x4A, 0x18, 0x00, 0xF6, 0x00, 0xEC, 0x3B, 0x01, 0x06, 0x01,
    0x0C, 0x32, 0x01, 0x22, 0x01, 0x24, 0x28, 0x00, 0x4F, 0x01, 0x0D, 0xD6, 0x00, 0x79, 0x00,
    0xA1, 0xFB, 0x40, 0x93, 0x00, 0xC5, 0xB1, 0x00, 0x54, 0x00, 0xDE, 0x49, 0x00, 0x52, 0x01,
    0x02, 0xD4, 0x00, 0x7E, 0x00, 0x7A, 0x76, 0x00, 0x77, 0x00, 0xA8, 0xB0, 0x00, 0x80, 0x01,
    0x3E, 0xE9, 0x00, 0xBA, 0x00, 0xFA, 0x48, 0x40, 0xDA, 0x00, 0xC2, 0x51, 0x00, 0xFE, 0x00,
    0x82, 0xCD, 0x41, 0x23, 0x00, 0x78, 0xC9, 0x01, 0x14, 0x01, 0x16, 0x2B, 0x00, 0xAE, 0x01,
    0x05, 0x46, 0x00, 0xD9, 0x01, 0x6F, 0x12, 0x00, 0x00
};

CK_BYTE updateFingerprint2[] = {
    0x46, 0x4D, 0x52, 0x00, 0x30, 0x33, 0x30, 0x00, 0x00, 0x00, 0x01, 0x5D, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0xC5, 0x00, 0x01, 0x40, 0x01, 0xE0,
0x50, 0x3C, 0x00, 0x26, 0x00, 0x58, 0x9F, 0x40, 0x36, 0x01, 0x60, 0xEB, 0x40, 0x5A, 0x01,
0x00, 0x42, 0x00, 0x9C, 0x00, 0x4C, 0x8D, 0x40, 0x9F, 0x01, 0x46, 0x8D, 0x00, 0xB8, 0x00,
0xF4, 0x32, 0x00, 0xC6, 0x01, 0x20, 0x28, 0x01, 0x08, 0x01, 0x34, 0x29, 0x41, 0x1D, 0x00,
0xDA, 0x39, 0x40, 0xD3, 0x00, 0x91, 0xC2, 0x00, 0xFA, 0x00, 0x43, 0xE9, 0x40, 0xFA, 0x00,
0xA3, 0xBF, 0x40, 0x27, 0x00, 0x6C, 0xA4, 0x00, 0x1F, 0x01, 0x2C, 0x56, 0x00, 0x5A, 0x00,
0x2E, 0x88, 0x40, 0x48, 0x00, 0xD2, 0x36, 0x00, 0x72, 0x01, 0x5E, 0x74, 0x40, 0x8E, 0x01,
0x06, 0x25, 0x40, 0x98, 0x00, 0xEA, 0x2E, 0x00, 0xB4, 0x00, 0x92, 0xBD, 0x00, 0x53, 0x01,
0x87, 0xF7, 0x40, 0xA7, 0x00, 0xBF, 0xB6, 0x00, 0xF0, 0x01, 0x5D, 0x9C, 0x01, 0x24, 0x00,
0xA5, 0xC2, 0x40, 0x2C, 0x00, 0x68, 0xAE, 0x00, 0x32, 0x01, 0x14, 0x4B, 0x40, 0x5A, 0x00,
0x9C, 0xB0, 0x00, 0x81, 0x00, 0x2E, 0x84, 0x40, 0x84, 0x00, 0xE8, 0x34, 0x00, 0xA3, 0x00,
0x7A, 0xA8, 0x40, 0xB6, 0x00, 0xDC, 0xB0, 0x00, 0xDA, 0x01, 0x84, 0x18, 0x01, 0x2D, 0x00,
0x66, 0xD1, 0x01, 0x1E, 0x00, 0x47, 0xE7, 0x40, 0x12, 0x00, 0xE2, 0x48, 0x00, 0x50, 0x00,
0x46, 0x91, 0x00, 0x6F, 0x00, 0x40, 0x91, 0x40, 0x62, 0x00, 0xC2, 0xB6, 0x00, 0x4B, 0x01,
0x40, 0x5E, 0x00, 0x8E, 0x00, 0x3A, 0x8D, 0x00, 0x56, 0x01, 0x7A, 0x6E, 0x00, 0x8E, 0x00,
0x7A, 0xA7, 0x40, 0x76, 0x00, 0xFA, 0x3B, 0x40, 0xA2, 0x00, 0x2A, 0x79, 0x40, 0x8A, 0x00,
0xAA, 0xB2, 0x40, 0x96, 0x00, 0xAA, 0xB4, 0x40, 0x7B, 0x01, 0x40, 0x70, 0x40, 0x86, 0x01,
0x0A, 0x3F, 0x40, 0xAB, 0x00, 0x80, 0xAD, 0x40, 0xAC, 0x00, 0x86, 0xB9, 0x00, 0xB8, 0x00,
0x6E, 0x70, 0x40, 0xB6, 0x00, 0xAA, 0x3B, 0x00, 0x9F, 0x01, 0x28, 0x8D, 0x00, 0xCE, 0x00,
0x42, 0xE8, 0x40, 0xD4, 0x00, 0x2E, 0xEB, 0x00, 0xCE, 0x00, 0x5A, 0xD8, 0x40, 0xF2, 0x00,
0x2A, 0xEE, 0x01, 0x04, 0x00, 0x4E, 0xDC, 0x40, 0xEA, 0x01, 0x82, 0x98, 0x01, 0x20, 0x01,
0x26, 0x25, 0x00, 0x00
};

void printBioAttributes(const CK_ATTRIBUTE attribute) {
    switch (attribute.type) {
    case CKA_VENDOR_RETRY_COUNT_LEFT:
        printf("CKA_VENDOR_RETRY_COUNT_LEFT               %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_VENDOR_MAX_RETRY_COUNT:
        printf("CKA_VENDOR_MAX_RETRY_COUNT                %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_VENDOR_FP_CONVOLUTIONS_COUNT:
        printf("CKA_VENDOR_FP_CONVOLUTIONS_COUNT          %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID:
        printf("CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID    %d\n", *(CK_BYTE*)attribute.pValue);
        break;
    case CKA_DESTROYABLE:
        printf("CKA_DESTROYABLE                           %s\n",
               *(CK_BBOOL*)attribute.pValue == CK_TRUE ? "TRUE" : "FALSE");
        break;
    case CKA_EXTRACTABLE:
        printf("CKA_EXTRACTABLE                           %s\n",
               *(CK_BBOOL*)attribute.pValue == CK_TRUE ? "TRUE" : "FALSE");
        break;
    case CKA_MODIFIABLE:
        printf("CKA_MODIFIABLE                            %s\n",
               *(CK_BBOOL*)attribute.pValue == CK_TRUE ? "TRUE" : "FALSE");
        break;
    default:
        return;
    }
}

static const char* fingerprintTypeToString(CK_BIO_FINGERPRINT_TYPE ft) {
switch (ft) {
case CK_BIO_FT_UNKNOWN:
return "unknown";
case CK_BIO_FT_RIGHT_THUMB:
return "right_thumb";
case CK_BIO_FT_RIGHT_INDEX:
return "right_index";
case CK_BIO_FT_RIGHT_MIDDLE:
return "right_middle";
case CK_BIO_FT_RIGHT_RING:
return "right_ring";
case CK_BIO_FT_RIGHT_LITTLE:
return "right_little";
case CK_BIO_FT_LEFT_THUMB:
return "left_thumb";
case CK_BIO_FT_LEFT_INDEX:
return "left_index";
case CK_BIO_FT_LEFT_MIDDLE:
return "left_middle";
case CK_BIO_FT_LEFT_RING:
return "left_ring";
case CK_BIO_FT_LEFT_LITTLE:
return "left_little";
default:
return "?";
}
}

#endif // BioCommon_H

Работа напрямую с Рутокен БИО

Получение информации о поддержке биометрической аутентификации 

Файл BioCheckToken.c
#include "BioCommon.h"

/************************************************************************
 * Шаблоны для поиска атрибута поддержки биометрии                      *
 ************************************************************************/
CK_ATTRIBUTE hardwareObjectTemplate[] = {
    { CKA_CLASS, &hardwareFeatureObject, sizeof(hardwareFeatureObject) },
    { CKA_HW_FEATURE_TYPE, &hardwareFeatureTokenInfo,
        sizeof(hardwareFeatureTokenInfo) }
};

CK_ULONG bioAuthSupportedTypes;

CK_ATTRIBUTE attributesTemplate = {
    CKA_VENDOR_BIOMETRIC_AUTHENTICATION, &bioAuthSupportedTypes,
        sizeof(bioAuthSupportedTypes)
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE_PTR features; // Массив найденных объектов характеристик токена
    CK_ULONG featuresCount;        // Количество объектов характеристик в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
        CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Проверить подходит ли целевой токен для работы с биометрией           *
     *************************************************************************/
    printf(" Checking for Biometric Authentication support...\n");
    r = findObjects(functionList, session, hardwareObjectTemplate,
        arraysize(hardwareObjectTemplate), &features, &featuresCount);
    CHECK_AND_LOG("  findObjects", r == 0, "", free_features);
CHECK_AND_LOG(" Features have been found", featuresCount > 0, "", logout);

    rv = functionList->C_GetAttributeValue(session, features[0], &attributesTemplate, 1);
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_features);

    CHECK_RELEASE(" Token supports Biometric Authentication",
        bioAuthSupportedTypes & BIOMETRIC_AUTHENTICATION_FINGERPRINT_CONVOLUTION, errorCode);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под объекты характеристик токена          *
     *************************************************************************/
free_features:
     free(features);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
logout:
     rv = functionList->C_Logout(session);
     CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
close_session:
     rv = functionList->C_CloseSession(session);
     CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
free_slots:
     free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
finalize_pkcs11:
     rv = functionList->C_Finalize(NULL_PTR);
     CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
     CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
     if (errorCode) {
         printf("\n\nSome error occurred. Sample failed.\n");
     } else {
        printf("\n\nSample has been completed successfully.\n");
     }

    return errorCode;
}

Первоначальное внесение набора отпечатков пальцев

Устройство должно поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.

Файл BioInitFingerprint.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона объекта набора отпечатков пальцев               *
 ************************************************************************/
CK_VENDOR_BUFFER fingerprints[] = {
    { initFingerprint, sizeof(initFingerprint) },
};
CK_ULONG fingerprintsCount = 2;
CK_ULONG maxRetryCount = 10;

CK_ATTRIBUTE fingerprintsTemplate[] = {
    { CKA_CLASS, &authObject,
        sizeof(authObject) },        // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) },          // Описание типа аутентификации создаваемого объекта -
                                     // свертка отпечатка пальца
    { CKA_VENDOR_FP_CONVOLUTIONS_COUNT, &fingerprintsCount,
        sizeof(fingerprintsCount) }, // Максимальное количество шаблонов в наборе.
                                     // Максимально разрешенное количество - 3 шаблона.
    { CKA_VENDOR_FP_CONVOLUTIONS, &fingerprints,
        sizeof(fingerprints) },      // Первоначальный набор отпечатков пальцев. Количество объектов
                                     // в массиве должно быть равно от 1 до значения fingerprintsCount.
    { CKA_VENDOR_MAX_RETRY_COUNT, &maxRetryCount,
        sizeof(maxRetryCount) }      // Максимальное количество неуспешных аутентификаций подряд.
                                     // Допустимые значения: от 1 до 10.
};

/************************************************************************
 * Формирование шаблона атрибутов для получения дополнительной          *
 * информации об объекте набора отпечатков пальцев                      *
 ************************************************************************/
CK_ULONG retryCountLeft;
CK_ULONG fpConvolutionId;
CK_BBOOL isDestroyable;
CK_BBOOL isExtractable;
CK_BBOOL isModifiable;

CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_RETRY_COUNT_LEFT, &retryCountLeft,
      sizeof(retryCountLeft) }, // Количество оставшихся попыток неуспешной аутентификации
                                // при помощи объекта.
                                // Сбрасывается до значения maxRetryCount при успешной аутентификации.
                                // При значении 0 объект является заблокированным, и не может
                                // использоваться для аутентификации до момента разблокировки.

    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
      sizeof(fpConvolutionId) }, // Идентификатор объекта набора отпечатков
    { CKA_DESTROYABLE, &isDestroyable, sizeof(isDestroyable) }, // Разрешено ли уничтожение объекта
                                                                // при помощи `C_DestroyObject`.
                                                                // Должно быть возвращено CK_FALSE

    { CKA_EXTRACTABLE, &isExtractable,
      sizeof(isExtractable) }, // Разрешено ли получение содержимого CKA_VENDOR_FP_CONVOLUTIONS
                               // при помощи `C_GetAttributeValue`. Должно быть возвращено CK_FALSE
    { CKA_MODIFIABLE, &isModifiable,
      sizeof(isModifiable) }, // Разрешено ли изменение содержимого CKA_VENDOR_FP_CONVOLUTIONS
                              // при помощи `C_SetAttributeValue`. Должно быть возвращено CK_TRUE
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE fingerprintsHandle; // Дескриптор набора отпечатков пальцев

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    CK_ULONG i;        // Вспомогательная переменная-счетчик в циклах
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Создать объект набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Creating fingerprints set...\n");
    rv = functionList->C_CreateObject(session, fingerprintsTemplate, arraysize(fingerprintsTemplate),
                                      &fingerprintsHandle);
    CHECK_AND_LOG("  C_CreateObject", rv == CKR_OK, rvToStr(rv), logout);

    printf(" Fingerprints set has been created successfully.\n");

    /*************************************************************************
     * Получить дополнительную информацию о наборе отпечатков пальцев        *
     *************************************************************************/
    printf(" Getting attributes of fingerprints set...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprintsHandle, attributeValueTemplate,
                                           arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Вывести значения атрибутов                                            *
     *************************************************************************/
    for (i = 0; i < arraysize(attributeValueTemplate); ++i) {
        printBioAttributes(attributeValueTemplate[i]);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}


Создание ключевой пары, защищенной отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
BioCreateKeyPair.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) }, // Описание типа аутентификации создаваемого объекта (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона для поиска значения атрибута идентификатора     *
 * в объекте набора отпечатков пальцев                                  *
 ************************************************************************/
CK_ULONG fpConvolutionId;

CK_ATTRIBUTE attributeValueTemplate[] = { { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
                                            sizeof(fpConvolutionId) } };

/*************************************************************************
 * Шаблон для генерации открытого ключа ГОСТ Р 34.10-2012(256)           *
 *************************************************************************/
CK_ATTRIBUTE publicKeyTemplate[] = {
    { CKA_CLASS, &publicKeyObject, sizeof(publicKeyObject) }, // Класс - открытый ключ
    { CKA_LABEL, &publicKeyLabelGost2012_256_1, sizeof(publicKeyLabelGost2012_256_1) - 1 }, // Метка ключа
    { CKA_ID, &keyPairIdGost2012_256_1,
        sizeof(keyPairIdGost2012_256_1) - 1 }, // Идентификатор ключевой пары
// (должен совпадать у открытого и закрытого ключей)
    { CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) }, // Тип ключа - ГОСТ Р 34.10-2012 (256)
    { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) }, // Ключ является объектом токена
    { CKA_PRIVATE, &attributeFalse, sizeof(attributeFalse) }, // Ключ доступен без аутентификации на токене
    { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) }, // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    { CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) } // Параметры алгоритма ГОСТ Р 34.11-2012(256)
};

/*************************************************************************
 * Шаблон для генерации закрытого ключа ГОСТ Р 34.10-2012(256)           *
 * с биометрической аутентификацией                                      *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) }, // Класс - закрытый ключ
    { CKA_LABEL, &privateKeyLabelGost2012_256_1,
        sizeof(privateKeyLabelGost2012_256_1) - 1 }, // Метка ключа
    { CKA_ID, &keyPairIdGost2012_256_1, // Идентификатор ключевой пары.
        sizeof(keyPairIdGost2012_256_1) - 1 }, // Должен совпадать у открытого и закрытого ключей
    { CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) },   // Тип ключа - ГОСТ Р 34.10-2012(256)
    { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) }, // Ключ является объектом токена
    { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue) }, // Ключ доступен только после
                                                            // аутентификации на токене
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) }, // Ключ можно использовать только после биометрической аутентификации
                                   // объектом с заданным id                                    
    { CKA_DERIVE, &attributeTrue, sizeof(attributeTrue) }, // Ключ поддерживает выработку
                                                           // ключей обмена (VKO)
    { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) }, // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    { CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) }, // Параметры алгоритма ГОСТ Р 34.11-2012(256)
    { CKA_START_DATE, &startDate, sizeof(startDate) }, // Дата начала срока действия закрытого ключа
    { CKA_END_DATE, &endDate, sizeof(startDate) }, // Дата окончания срока действия закрытого ключа
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии
    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_MECHANISM_TYPE_PTR mechanisms; // Массив поддерживаемых механизмов
    CK_ULONG mechanismCount;          // Количество поддерживаемых механизмов
    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве
    CK_OBJECT_HANDLE
    publicKey;  // Дескриптор открытого ключа
                // ГОСТ Р 34.10-2012(256) (первая ключевая пара для подписи и обмена ключами)
    CK_OBJECT_HANDLE
    privateKey; // Дескриптор закрытого ключа
                // ГОСТ Р 34.10-2012(256) (первая ключевая пара для подписи и обмена ключами)

    CK_RV rv;   // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;      // Код возврата для функций, возвращающих int
    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах
    int isGostR3410Supported = 0; // Флаг для проверки поддержки токеном CKM_GOSTR3410_KEY_PAIR_GEN
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);
    CHECK_AND_LOG(" Checking available tokens",
slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Получить список поддерживаемых токеном механизмов                     *
     *************************************************************************/
    rv = functionList->C_GetMechanismList(slots[0], NULL_PTR, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList (number of mechanisms)", rv == CKR_OK, rvToStr(rv), free_slots);
    CHECK_AND_LOG(" Checking mechanisms available", mechanismCount > 0,
        " No mechanisms available", free_slots);

    mechanisms = (CK_MECHANISM_TYPE_PTR)malloc(mechanismCount * sizeof(CK_MECHANISM_TYPE));
    CHECK(" Memory allocation for mechanisms", mechanisms != NULL_PTR, free_slots);

    rv = functionList->C_GetMechanismList(slots[0], mechanisms, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList", rv == CKR_OK, rvToStr(rv), free_mechanisms);

    /*************************************************************************
     * Определение поддерживаемых токеном механизмов                         *
     *************************************************************************/
    for (i = 0; i < mechanismCount; ++i) {
        if (mechanisms[i] == CKM_GOSTR3410_KEY_PAIR_GEN) {
            isGostR3410Supported = 1;
            break;
        }
    }

    CHECK_AND_LOG(" Checking CKM_GOSTR3410_KEY_PAIR_GEN support", isGostR3410Supported,
                  "CKM_GOSTR3410_KEY_PAIR_GEN isn`t supported!\n", free_mechanisms);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /*************************************************************************
     * Получение значения атрибута идентификатора из первого найденного      *
     * объекта набора отпечатков пальцев                                     *
     *************************************************************************/
    printf(" Getting fingerprints set convolution ID value...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[0],
        attributeValueTemplate, arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Сгенерировать ключевую пару ГОСТ Р 34.10-2012(256)                    *
     *************************************************************************/
    printf(" Generating GOST R 34.10-2012(256) exchange key pairs...\n");
    rv = functionList->C_GenerateKeyPair(session, &gostR3410_2012_256KeyPairGenMech, publicKeyTemplate,
arraysize(publicKeyTemplate), privateKeyTemplate, arraysize(privateKeyTemplate),
&publicKey, &privateKey);
    CHECK_AND_LOG("  C_GenerateKeyPair", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;
    printf("Generation has been completed successfully.\n");

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под объекты набора отпечатков пальцев     *
     *************************************************************************/
    free_fingerprints:
        free(fingerprints);

   
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
  logout:      
rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/
    free_mechanisms:
        free(mechanisms);

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Проверка, что закрытый ключ (ключевая пара) защищен отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
  3. Содержать объект ключевой пары, защищённый биометрией. Создание объекта описано в примере BioCreateKeyPair.c.
Файл BioCheckKeyPair.c
#include <BioCommon.h>

/*************************************************************************
 * Шаблон для поиска атрибута идентификатора отпечатка пальцев           *
 * в объекте закрытого ключа                                             *
 *************************************************************************/
CK_ATTRIBUTE attrConvolutionsIdTemplate[] = { { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, NULL_PTR, 0 } };

/*************************************************************************
 * Шаблон для поиска атрибута идентификатора пары в объекте              *
 * закрытого ключа                                                       *
 *************************************************************************/
CK_ATTRIBUTE attrPairIdTemplate[] = { { CKA_ID, NULL_PTR, 0 } };

/*************************************************************************
 * Шаблон для поиска закрытого ключа для цифровой подписи                *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) }, // Класс - закрытый ключ
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE_PTR privateKeys; // Массив дескрипторов объектов закрытых ключей
    CK_ULONG privateKeysCount; // Количество дескрипторов объектов закрытых ключей

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11

    int r; // Код возврата для функций, возвращающих int

    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах

    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск всех закрытых ключей. Также можно сначала найти открытый ключ   *
     * пары по атрибуту CKA_VALUE и затем найти закрытый ключ по атрибуту    *
     * CKA_ID открытого ключа                                                *
     *************************************************************************/
    printf(" Getting private keys...\n");
    r = findObjects(functionList, session, privateKeyTemplate, arraysize(privateKeyTemplate),
        &privateKeys, &privateKeysCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_privateKeys);
CHECK_AND_LOG(" Private keys (key pairs) have been found", privateKeysCount > 0, "", logout);

    /*************************************************************************
     * Проверка всех найденных закрытых ключей (ключевых пар)                *
     * на защиту отпечатком пальцев                                          *
     *************************************************************************/
    printf(" Checking private keys (key pairs) for protection by Biometric Authentication...\n");
    for (i = 0; i < privateKeysCount; ++i) {
        free(attrPairIdTemplate->pValue);
        attrPairIdTemplate->pValue = NULL_PTR;

        /*************************************************************************
         * Получение длины значения атрибута идентификатора пары ключей          *
         *************************************************************************/
        rv = functionList->C_GetAttributeValue(session, privateKeys[i], attrPairIdTemplate, 1);
        CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_privateKeys);

        /*************************************************************************
         * Выделение памяти под значение атрибута идентификатора пары ключей     *
         *************************************************************************/
        attrPairIdTemplate->pValue = (CK_VOID_PTR)malloc(attrPairIdTemplate->ulValueLen);
        CHECK_AND_LOG("  Memory allocation for pair ID value",
            attrPairIdTemplate->pValue != NULL, rvToStr(rv), free_privateKeys);

        /*************************************************************************
         * Получение значения атрибута идентификатора пары                       *
         *************************************************************************/
        rv = functionList->C_GetAttributeValue(session, privateKeys[i], attrPairIdTemplate, 1);
        CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_pairId);

        /*************************************************************************
         * Получение атрибута идентификатора отпечатка пальцев                   *
         *************************************************************************/
        rv = functionList->C_GetAttributeValue(session, privateKeys[i], attrConvolutionsIdTemplate, 1);
        CHECK_RELEASE("  C_GetAttributeValue", rv == CKR_OK, errorCode);

        /**************************************************************************
         * Вывод сообщения с результатом проверки закрытого ключа (ключевой пары) *
         **************************************************************************/
        printf(" Private key (key pair) with ID *%.*s* %s biometric authentication.\n\n",
               (int)attrPairIdTemplate->ulValueLen, (CK_BYTE*)attrPairIdTemplate->pValue,
               (rv == CKR_OK ? " supports" : " dose not support"));
    }
    if (privateKeysCount > 0)
        printf("All private keys (key pairs) are checked.\n");
    else
        printf("No private keys (key pairs) found.\n");

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Очистить память, выделенную под атрибуты объект                       *
     *************************************************************************/
    free_pairId:
        free(attrPairIdTemplate->pValue);

    /*************************************************************************
     * Очистить память, выделенную под объекты                               *
     *************************************************************************/
    free_privateKeys:
        free(privateKeys);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
    logout:
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Использование ключевой пары, защищенной отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
  3. Содержать объект ключевой пары, защищённый биометрией. Создание объекта описано в примере BioCreateKeyPair.c.
Файл BioUseKeyPair.c
#include "BioCommon.h"

/*************************************************************************
 * Данные для хеширования и цифровой подписи                             *
 *************************************************************************/
CK_BYTE data[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) }, // Описание типа аутентификации
// создаваемого объекта (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона для поиска значения атрибута идентификатора     *
 * в объекте набора отпечатков пальцев                                  *
 ************************************************************************/
CK_ULONG fpConvolutionId;

CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId, sizeof(fpConvolutionId) }
};

/*************************************************************************
 * Шаблон для поиска закрытого ключа для цифровой подписи                *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_ID, &keyPairIdGost2012_256_1, sizeof(keyPairIdGost2012_256_1) - 1 }, // ID пары
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) },                // Класс - закрытый ключ
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) }, // ID объекта набора отпечатков пальцев,
                                   // который использовался для биометрической аутентификации
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
                                       // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_MECHANISM_TYPE_PTR mechanisms; // Массив поддерживаемых механизмов
    CK_ULONG mechanismCount;          // Количество поддерживаемых механизмов

    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_OBJECT_HANDLE_PTR privateKeys; // Массив дескрипторов объектов закрытых ключей
    CK_ULONG privateKeysCount; // Количество дескрипторов объектов закрытых ключей

    CK_BYTE_PTR signature; // Указатель на буфер, содержащий цифровую подпись для данных
    CK_ULONG signatureSize; // Размер буфера, содержащего цифровую подпись для данных, в байтах

    CK_BYTE_PTR hash;  // Указатель на временный буфер для хеш-кода от данных
    CK_ULONG hashSize; // Размер временного буфера в байтах

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11

    int r; // Код возврата для функций, возвращающих int

    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах

    int isGostR3410Supported = 0; // Флаг для проверки поддержки токеном CKM_GOSTR3410_KEY_PAIR_GEN

    int fingerprintIndex = -1; // Индекс объекта набора отпечатка пальцев,
                               // соответствующий переданному отпечатку

    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
"C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Получить список поддерживаемых токеном механизмов                     *
     *************************************************************************/
    rv = functionList->C_GetMechanismList(slots[0], NULL_PTR, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList (number of mechanisms)", rv == CKR_OK, rvToStr(rv), free_slots);

    CHECK_AND_LOG(" Checking mechanisms available",
mechanismCount > 0, " No mechanisms available", free_slots);

    mechanisms = (CK_MECHANISM_TYPE_PTR)malloc(mechanismCount * sizeof(CK_MECHANISM_TYPE));
    CHECK(" Memory allocation for mechanisms", mechanisms != NULL_PTR, free_slots);

    rv = functionList->C_GetMechanismList(slots[0], mechanisms, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList", rv == CKR_OK, rvToStr(rv), free_mechanisms);

    /*************************************************************************
     * Определение поддерживаемых токеном механизмов                         *
     *************************************************************************/
    for (i = 0; i < mechanismCount; ++i) {
        if (mechanisms[i] == CKM_GOSTR3410_KEY_PAIR_GEN) {
            isGostR3410Supported = 1;
            break;
        }
    }

    CHECK_AND_LOG(" Checking CKM_GOSTR3410_KEY_PAIR_GEN support", isGostR3410Supported,
                  "CKM_GOSTR3410_KEY_PAIR_GEN isn`t supported!\n", free_mechanisms);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

/*************************************************************************
* Повторная попытка аутентификации для набора отпечатков, *
* обновленного с помощью примера BioUpdateFingerprint *
*************************************************************************/
rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
initFingerprint, sizeof(initFingerprint));

if (rv == CKR_PIN_INCORRECT)
rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
updateFingerprint1, sizeof(updateFingerprint1));
CHECK_AND_LOG(" C_EX_Authenticate", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /************************************************************************
     * Получение значения атрибута идентификатора из первого найденного   *
     * объекта набора отпечатков пальцев                                    *
     ************************************************************************/
    printf(" Getting fingerprints set convolution ID value...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[fingerprintIndex],
        attributeValueTemplate, arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), deauthenticate);

    /*************************************************************************
     * Поиск закрытого ключа, соответствующего набору отпечатков пальцев      *
     *************************************************************************/
    printf(" Getting private keys...\n");
    r = findObjects(functionList, session, privateKeyTemplate,
        arraysize(privateKeyTemplate), &privateKeys, &privateKeysCount);
    CHECK_AND_LOG("  findObjects", r == 0, "", free_privateKeys);
    CHECK_AND_LOG(" Private keys have been found", privateKeysCount > 0, "", deauthenticate);

    /*************************************************************************
     * Вычислить хеш-код данных                                              *
     *************************************************************************/
    printf(" Hashing data...\n");

    /*************************************************************************
     * Инициализировать хеш-функцию                                          *
     *************************************************************************/
    rv = functionList->C_DigestInit(session, &gostR3411_2012_256HashMech);
    CHECK_AND_LOG("  C_DigestInit", rv == CKR_OK, rvToStr(rv), free_privateKeys);

    /*************************************************************************
     * Определить размер хеш-кода                                            *
     *************************************************************************/
    rv = functionList->C_Digest(session, data, sizeof(data), NULL_PTR, &hashSize);
    CHECK_AND_LOG("  C_Digest(get size)", rv == CKR_OK, rvToStr(rv), free_privateKeys);

    /*************************************************************************
     * Вычислить хеш-код данных                                              *
     *************************************************************************/

    hash = (CK_BYTE*)malloc(hashSize * sizeof(CK_BYTE));
    CHECK("  Memory allocation for hash", hash != NULL, free_privateKeys);

    rv = functionList->C_Digest(session, data, sizeof(data), hash, &hashSize);
    CHECK_AND_LOG("  C_Digest (get hash)", rv == CKR_OK, rvToStr(rv), free_hash);

    /*************************************************************************
     * Распечатать буфер, содержащий хеш-код                                 *
     *************************************************************************/
    printf("  Hashed buffer is: \n");
    printHex(hash, hashSize);
    printf("  Hashing has been completed.\n");

    /*************************************************************************
     * Сформировать цифровую подпись данных                                  *
     * по алгоритму ГОСТ Р 34.10-2012(256)                                   *
     *************************************************************************/
    printf(" Signing data...\n");
    /*************************************************************************
     * Инициализировать операцию подписи данных                              *
     *************************************************************************/
    rv = functionList->C_SignInit(session, &gostR3410_2012_256SigVerMech, privateKeys[0]);
    CHECK_AND_LOG("  C_SignInit", rv == CKR_OK, rvToStr(rv), free_hash);

    /*************************************************************************
     * Определить размер данных подписи                                      *
     *************************************************************************/
    rv = functionList->C_Sign(session, hash, hashSize, NULL_PTR, &signatureSize);
    CHECK_AND_LOG("  C_Sign (get size)", rv == CKR_OK, rvToStr(rv), free_hash);

    /*************************************************************************
     * Подписать данные                                                      *
     *************************************************************************/
    signature = (CK_BYTE*)malloc(signatureSize * sizeof(CK_BYTE));
    CHECK("  Memory allocation for signature", signature != NULL, free_hash);

    rv = functionList->C_Sign(session, hash, hashSize, signature, &signatureSize);
    CHECK_AND_LOG("  C_Sign (signing)", rv == CKR_OK, rvToStr(rv), free_signature);

    /*************************************************************************
     * Распечатать буфер, содержащий подпись                                 *
     *************************************************************************/
    printf("  Signature buffer is: \n");
    printHex(signature, signatureSize);
    printf("  Data has been signed successfully.\n");

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под хеш-коды, подпись и объекты           *
     *************************************************************************/
    free_signature:
        free(signature);

    free_hash:
        free(hash);

    free_privateKeys:
        free(privateKeys);

  /************************************************************************
* Деаутентификация при помощи найденного объекта набора отпечатков *
************************************************************************/  
    deauthenticate:
rv = functionListEx->C_EX_Deauthenticate(session, fingerprints[0]);
CHECK_RELEASE_AND_LOG(" C_EX_Deauthenticate", rv == CKR_OK, rvToStr(rv), errorCode);

/************************************************************************
* Очистить память, выделенную под объекты наборов отпечатков *
************************************************************************/
free_fingerprints:
free(fingerprints);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
    logout:
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/
    free_mechanisms:
        free(mechanisms);

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Сброс счетчика попыток применения отпечатка

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
Файл BioResetAttempts.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
      sizeof(authType) }, // Описание типа аутентификации создаваемого объекта (свертка отпечатка пальца)
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    CK_ULONG i;        // Вспомогательная переменная-счетчик в циклах
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
        "C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
    CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /*************************************************************************
     * Сброс счетчика попыток использования у всех объектов                  *
     *************************************************************************/
    printf(" Resetting fingerprints sets use attempts counter...\n");
    for (i = 0; i < fingerprintsCount; ++i) {
        rv = functionListEx->C_EX_UnblockAuthenticator(session, fingerprints[i]);
        CHECK_AND_LOG("  C_EX_UnblockAuthenticator", rv == CKR_OK, rvToStr(rv), logout);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

/*************************************************************************
* Очистить память, выделенную под объекты наборов отпечатков *
*************************************************************************/
free_fingerprints:
free(fingerprints);
    logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Получение информации об объекте набора отпечатков пальцев

Файл BioGetInfo.c
#include <BioCommon.h>

/************************************************************************
 * Шаблоны для поиска объекта набора отпечатков пальцев                 *
 ************************************************************************/
CK_ATTRIBUTE authenticationObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
      sizeof(authType) }, // Описание типа аутентификации, поиск которого
                          // осуществляется (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона атрибутов для получения информации              *
 * об объекте набора отпечатков пальцев                                 *
 ************************************************************************/
CK_ULONG retryCountLeft;
CK_ULONG maxRetryCountLeft;
CK_ULONG fpConvolutionId;
CK_ULONG fingerprintsCount;

CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_RETRY_COUNT_LEFT, &retryCountLeft,
        sizeof(retryCountLeft) }, // Количество оставшихся попыток неуспешной
                                  // аутентификации при помощи объекта. Сбрасывается
                                  // до значения maxRetryCount при успешной
                                  // аутентификации. При значении 0 объект является
                                  // заблокированным, и не может использоваться для
                                  // аутентификации до момента разблокировки
    { CKA_VENDOR_MAX_RETRY_COUNT, &maxRetryCountLeft,
        sizeof(maxRetryCountLeft) }, // Максимальное количество попыток для объекта набора отпечатков
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) },   // Идентификатор объекта набора отпечатков
    { CKA_VENDOR_FP_CONVOLUTIONS_COUNT, &fingerprintsCount,
        sizeof(fingerprintsCount) }, // Максимальное количество шаблонов в наборе
                                     // Максимально разрешенное количество - 3
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsObjectsCount; // Количество дескрипторов объектов набора
                                       // отпечатков пальцев в массиве

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authenticationObjectTemplate,
            arraysize(authenticationObjectTemplate), &fingerprints, &fingerprintsObjectsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsObjectsCount > 0, "", logout);

    /*************************************************************************
     * Получить дополнительную информацию о наборе отпечатков пальцев       *
     *************************************************************************/
    printf(" Getting attributes of fingerprints set...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[0], attributeValueTemplate,
                                           arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Вывести значения атрибутов                                            *
     *************************************************************************/
    for (CK_ULONG i = 0; i < arraysize(attributeValueTemplate); ++i) {
        printBioAttributes(attributeValueTemplate[i]);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под объекты наборов отпечатков            *
     *************************************************************************/
    free_fingerprints:
        free(fingerprints);

    logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Обновление занесенного отпечатка с применением отпечатка пользователя

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.

После выполнения данного примера остальные примеры, использующие для аутентификации изначальный шаблон (initFingerprint), перестанут работать. Создайте новый набор отпечатков (пример BioInitFingerprint.c) или используйте для аутентификации один из новых отпечатков (updateFingerprint1, updateFingerprint2 из примера BioInitFingerprint.c).

Файл BioUpdateFingerprint.c
#include "BioCommon.h"

/************************************************************************
 * Шаблоны для поиска объекта набора отпечатков пальцев                 *
 ************************************************************************/
CK_ATTRIBUTE authenticationObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
        sizeof(authType) },               // Описание типа аутентификации,
                                          // поиск которого осуществляется (свертка отпечатка пальца)
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r;    // Код возврата для функций, возвращающих int
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
         "C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authenticationObjectTemplate,
        arraysize(authenticationObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /*************************************************************************
     * Аутентификация при помощи найденного объекта набора отпечатков        *
     *************************************************************************/
    rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
initFingerprint, sizeof(initFingerprint));
    CHECK_AND_LOG("  C_EX_Authenticate", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Замена существующего набора отпечатков в объекте на новый             *
     *************************************************************************/
    CK_VENDOR_BUFFER newFingerprints[] = {
        { updateFingerprint1, sizeof(updateFingerprint1) },
        { updateFingerprint2, sizeof(updateFingerprint2) }
    };

    CK_ATTRIBUTE fingerprintsUpdateTemplate[] = {
        { CKA_VENDOR_FP_CONVOLUTIONS, &newFingerprints, sizeof(newFingerprints) } };

    rv = functionList->C_SetAttributeValue(session, fingerprints[0], fingerprintsUpdateTemplate, 1);
    CHECK_AND_LOG("  C_SetAttributeValue", rv == CKR_OK, rvToStr(rv), deauthenticate);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");


/************************************************************************
* Деаутентификация при помощи найденного объекта набора отпечатков *
************************************************************************/
deauthenticate:
rv = functionListEx->C_EX_Deauthenticate(session, fingerprints[0]);
CHECK_RELEASE_AND_LOG(" C_EX_Deauthenticate", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под объекты наборов отпечатков            *
     *************************************************************************/
    free_fingerprints:
      free(fingerprints);

    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
logout:
    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                                 *
     *************************************************************************/
    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}

Удаление ключевой пары, защищенной отпечатком

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
  3. Содержать объект ключевой пары, защищённый биометрией. Создание объекта описано в примере BioCreateKeyPair.c.
Файл BioDeleteKeyPair.c
#include "BioCommon.h"

/************************************************************************
 * Формирование шаблона для поиска объекта набора отпечатков пальцев    *
 ************************************************************************/
CK_ATTRIBUTE authObjectTemplate[] = {
    { CKA_CLASS, &authObject, sizeof(authObject) }, // Класс - Authentication Object
    { CKA_VENDOR_AUTHENTICATION_FACTOR_TYPE, &authType,
      sizeof(authType) }, // Описание типа аутентификации создаваемого объекта (свертка отпечатка пальца)
};

/************************************************************************
 * Формирование шаблона для поиска значения атрибута идентификатора     *
 * в объекте набора отпечатков пальцев                                  *
 ************************************************************************/
CK_ULONG fpConvolutionId;
CK_ATTRIBUTE attributeValueTemplate[] = {
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId, sizeof(fpConvolutionId) }
};

/*************************************************************************
 * Шаблон для генерации открытого ключа ГОСТ Р 34.10-2012(256)           *
 *************************************************************************/
CK_ATTRIBUTE publicKeyTemplate[] = {
    {CKA_CLASS, &publicKeyObject, sizeof(publicKeyObject) }, // Класс - открытый ключ
    {CKA_LABEL, &publicKeyLabelGost2012_256_1, sizeof(publicKeyLabelGost2012_256_1) - 1 }, // Метка ключа
    {CKA_ID, &keyPairIdGost2012_256_1,
        sizeof(keyPairIdGost2012_256_1) - 1 },               // Идентификатор ключевой пары
    {CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) },                 // Тип ключа - ГОСТ Р 34.10-2012(256)
    {CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) },     // Ключ является объектом токена
    {CKA_PRIVATE, &attributeFalse, sizeof(attributeFalse) }, // Ключ доступен без аутентификации на токене
    {CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) },              // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    {CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) }               // Параметры алгоритма ГОСТ Р 34.11-2012(256)
};

/*************************************************************************
 * Шаблон для генерации закрытого ключа ГОСТ Р 34.10-2012(256)           *
 * с биометрической аутентификацией                                      *
 *************************************************************************/
CK_ATTRIBUTE privateKeyTemplate[] = {
    { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject) }, // Класс - закрытый ключ
    { CKA_LABEL, &privateKeyLabelGost2012_256_1,
        sizeof(privateKeyLabelGost2012_256_1) - 1 },            // Метка ключа
    { CKA_ID, &keyPairIdGost2012_256_1,
        sizeof(keyPairIdGost2012_256_1) - 1 },                  // Идентификатор ключевой пары
    { CKA_KEY_TYPE, &keyTypeGostR3410_2012_256,
        sizeof(keyTypeGostR3410_2012_256) },              // Тип ключа - ГОСТ Р 34.10-2012(256)
    { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue) }, // Ключ является объектом токена
    { CKA_PRIVATE, &attributeTrue,
        sizeof(attributeTrue) },                // Ключ доступен только после аутентификации на токене
    { CKA_VENDOR_FINGERPRINT_CONVOLUTIONS_ID, &fpConvolutionId,
        sizeof(fpConvolutionId) },      // Ключ можно использовать только
                                        // после биометрической аутентификации объектом с заданным id
    { CKA_DERIVE, &attributeTrue,
        sizeof(attributeTrue) },        // Ключ поддерживает выработку ключей обмена (VKO)
    { CKA_GOSTR3410_PARAMS, parametersGostR3410_2012_256,
        sizeof(parametersGostR3410_2012_256) }, // Параметры алгоритма ГОСТ Р 34.10-2012(256)
    { CKA_GOSTR3411_PARAMS, parametersGostR3411_2012_256,
        sizeof(parametersGostR3411_2012_256) }, // Параметры алгоритма ГОСТ Р 34.11-2012(256)
    { CKA_START_DATE, &startDate, sizeof(startDate) }, // Дата начала срока действия закрытого ключа
    { CKA_END_DATE, &endDate, sizeof(startDate) },     // Дата окончания срока действия закрытого ключа
};

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии
    CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_FUNCTION_LIST_EXTENDED_PTR functionListEx; // Указатель на список функций расширения PKCS#11,
                                                  // хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на C_EX_GetFunctionListExtended
    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_MECHANISM_TYPE_PTR mechanisms; // Массив поддерживаемых механизмов
    CK_ULONG mechanismCount;          // Количество поддерживаемых механизмов
    CK_OBJECT_HANDLE_PTR fingerprints; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG fingerprintsCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве
    CK_OBJECT_HANDLE_PTR pubKeys; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG pubKeysCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве
    CK_OBJECT_HANDLE_PTR priKeys; // Массив найденных объектов набора отпечатков пальцев
    CK_ULONG priKeysCount; // Количество дескрипторов объектов набора отпечатков пальцев в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int r; // Код возврата для функций, возвращающих int
    CK_ULONG i; // Вспомогательная переменная-счетчик в циклах

    int isGostR3410Supported = 0; // Флаг для проверки поддержки токеном CKM_GOSTR3410_KEY_PAIR_GEN
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * расширенные функции                                                   *
     *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module,
"C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress", getFunctionListEx != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на расширенные функции               *
     *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);
    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Получить список поддерживаемых токеном механизмов                     *
     *************************************************************************/
    rv = functionList->C_GetMechanismList(slots[0], NULL_PTR, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList (number of mechanisms)", rv == CKR_OK, rvToStr(rv), free_slots);
    CHECK_AND_LOG(" Checking mechanisms available",
mechanismCount > 0, " No mechanisms available", free_slots);

    mechanisms = (CK_MECHANISM_TYPE_PTR)malloc(mechanismCount * sizeof(CK_MECHANISM_TYPE));
    CHECK(" Memory allocation for mechanisms", mechanisms != NULL_PTR, free_slots);

    rv = functionList->C_GetMechanismList(slots[0], mechanisms, &mechanismCount);
    CHECK_AND_LOG(" C_GetMechanismList", rv == CKR_OK, rvToStr(rv), free_mechanisms);

    /*************************************************************************
     * Определение поддерживаемых токеном механизмов                         *
     *************************************************************************/
    for (i = 0; i < mechanismCount; ++i) {
        if (mechanisms[i] == CKM_GOSTR3410_KEY_PAIR_GEN) {
            isGostR3410Supported = 1;
            break;
        }
    }

    CHECK_AND_LOG(" Checking CKM_GOSTR3410_KEY_PAIR_GEN support", isGostR3410Supported,
                  "CKM_GOSTR3410_KEY_PAIR_GEN isn`t supported!\n", free_mechanisms);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                            *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
        NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Поиск объектов набора отпечатков пальцев на токене                    *
     *************************************************************************/
    printf(" Getting fingerprints sets...\n");
    r = findObjects(functionList, session, authObjectTemplate,
        arraysize(authObjectTemplate), &fingerprints, &fingerprintsCount);
    CHECK_AND_LOG(" findObjects", r == 0, "", free_fingerprints);
CHECK_AND_LOG(" Fingerprints sets have been found", fingerprintsCount > 0, "", logout);

    /************************************************************************
     * Получение значения атрибута идентификатора из первого найденного     *
     * объекта набора отпечатков пальцев                                    *
     ************************************************************************/
    printf(" Getting fingerprints set convolution ID value...\n");
    rv = functionList->C_GetAttributeValue(session, fingerprints[0], attributeValueTemplate,
                                           arraysize(attributeValueTemplate));
    CHECK_AND_LOG("  C_GetAttributeValue", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    rv = functionListEx->C_EX_Authenticate(session, fingerprints[0], 
initFingerprint, sizeof(initFingerprint));

/************************************************************************
* Повторная попытка аутентификации для набора отпечатков, обновленного *
* с помощью примера BioUpdateFingerprint *
************************************************************************/
if (rv == CKR_PIN_INCORRECT) rv = functionListEx->C_EX_Authenticate(session, fingerprints[0],
updateFingerprint1, sizeof(updateFingerprint1));
CHECK_AND_LOG(" C_EX_Authenticate", rv == CKR_OK, rvToStr(rv), free_fingerprints);

    /*************************************************************************
     * Поиск объектов ключевой пары на токене.                               *
     * Предполагается наличие одной ключевой пары с заданными параметрами    *
     *************************************************************************/
    printf(" Getting private key...\n");
    r = findObjects(functionList, session, privateKeyTemplate,
        arraysize(privateKeyTemplate), &priKeys, &priKeysCount);
CHECK_AND_LOG(" findObjects", (r == 0), "", free_prikeys);
CHECK_AND_LOG(" Private keys have been found", priKeysCount > 0, "", deauthenticate);

    printf(" Getting public key...\n");
    r = findObjects(functionList, session, publicKeyTemplate,
        arraysize(publicKeyTemplate), &pubKeys, &pubKeysCount);
    CHECK_AND_LOG(" findObjects", (r == 0), "", free_pubkeys);
CHECK_AND_LOG(" Public keys have been found", pubKeysCount > 0, "", free_prikeys);

    /*************************************************************************
     * Удаление объектов ключевой пары с токена                              *
     *************************************************************************/
    printf(" Deleting private key...\n");
    rv = functionList->C_DestroyObject(session, priKeys[0]);
    CHECK_AND_LOG("  C_DestroyObject", rv == CKR_OK, rvToStr(rv), free_pubkeys);

    printf(" Deleting public key...\n");
    rv = functionList->C_DestroyObject(session, pubKeys[0]);
    CHECK_AND_LOG("  C_DestroyObject", rv == CKR_OK, rvToStr(rv), free_pubkeys);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;
    printf("Generation has been completed successfully.\n");

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");
   
    /*************************************************************************
     * Очистить память, выделенную под объекты открытых ключей               *
     *************************************************************************/
free_pubkeys:
        free(pubKeys);

    /*************************************************************************
     * Очистить память, выделенную под объекты закрытых ключей               *
     *************************************************************************/
free_prikeys:
        free(priKeys);


/*************************************************************************
* Деаутентификация при помощи найденного объекта набора отпечатков *
*************************************************************************/
deauthenticate:
rv = functionListEx->C_EX_Deauthenticate(session, fingerprints[0]);
CHECK_RELEASE_AND_LOG(" C_EX_Deauthenticate", rv == CKR_OK, rvToStr(rv), errorCode);


    /*************************************************************************
     * Очистить память, выделенную под объекты набора отпечатков пальцев     *
     *************************************************************************/
free_fingerprints:
        free(fingerprints);
 
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
logout:
        rv = functionList->C_Logout(session);
        CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
    close_session:
        rv = functionList->C_CloseSession(session);
        CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты и механизмы                     *
     *************************************************************************/
    free_mechanisms:
        free(mechanisms);

    free_slots:
        free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                         *
     *************************************************************************/
    finalize_pkcs11:
        rv = functionList->C_Finalize(NULL_PTR);
        CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
    unload_pkcs11:
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

    exit:
        if (errorCode) {
            printf("\n\nSome error occurred. Sample failed.\n");
        } else {
            printf("\n\nSample has been completed successfully.\n");
        }

    return errorCode;
}


Работа с Рутокен БИО и сканерами в PKCS#11 через BioLib

Получение cписка доступных адаптеров сканеров

Файл CBioListScannersAdapters.c
#include <BioCommon.h>

int main(void) {
HMODULE module; // Дескриптор загруженной библиотеки PKCS#11

CK_FUNCTION_LIST_PTR functionList; // Указатель на список функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST
CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
// хранящийся в структуре CK_FUNCTION_LIST_BIO
CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

CK_BIO_SCANNERS_ADAPTER_INFO_PTR adaptersInfo; // Массив информации об адаптерах сканеров
CK_ULONG adaptersInfoCount; // Размер массива информации об адаптерах сканеров

CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
int errorCode = 1; // Флаг ошибки

/*************************************************************************
* Выполнить действия для начала работы с библиотекой PKCS#11 *
*************************************************************************/
printf("Initialization...\n");

/*************************************************************************
* Загрузить библиотеку *
*************************************************************************/
module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
CHECK(" LoadLibrary", module != NULL, exit);

/*************************************************************************
* Получить адрес функции запроса структуры с указателями на функции *
*************************************************************************/
getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

/*************************************************************************
* Получить структуру с указателями на функции *
*************************************************************************/
rv = getFunctionList(&functionList);
CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

/*************************************************************************
* Получить адрес функции запроса структуры с указателями на *
* биометрические функции *
*************************************************************************/
getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

/*************************************************************************
* Получить структуру с указателями на биометрические функции *
*************************************************************************/
rv = getFunctionListBio(&functionListBio);
CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

/*************************************************************************
* Инициализировать библиотеку *
*************************************************************************/
rv = functionList->C_Initialize(&initArgs);
CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

/*************************************************************************
* Инициализировать биометрический функционал *
*************************************************************************/
rv = functionListBio->C_BIO_Initialize(0);
CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

/*************************************************************************
* Получить информацию об адаптерах сканеров *
*************************************************************************/
rv = functionListBio->C_BIO_ListScannersAdapters(NULL, &adaptersInfoCount);
CHECK_AND_LOG(" C_BIO_ListScannersAdapters", rv == CKR_OK, rvToStr(rv), finalize_bio);

adaptersInfo = (CK_BIO_SCANNERS_ADAPTER_INFO_PTR)
malloc(adaptersInfoCount * sizeof(CK_BIO_SCANNERS_ADAPTER_INFO));
CHECK(" Memory allocation for adapters info", adaptersInfo != NULL, finalize_bio);

rv = functionListBio->C_BIO_ListScannersAdapters(adaptersInfo, &adaptersInfoCount);
CHECK_AND_LOG(" C_BIO_ListScannersAdapters", rv == CKR_OK, rvToStr(rv), free_adaptersInfo);

/*************************************************************************
* Вывести информацию об адаптерах сканеров *
*************************************************************************/
printf("\n");
for (CK_ULONG i = 0; i < adaptersInfoCount; ++i) {
printf("%3lu. %-10s: %s \n", i + 1, adaptersInfo[i].name,
adaptersInfo[i].available ? "available" : "not available");
}
printf("\n");

/*************************************************************************
* Выставить признак успешного завершения программы *
*************************************************************************/
errorCode = 0;

/*************************************************************************
* Выполнить действия для завершения работы с библиотекой PKCS#11 *
*************************************************************************/
printf("\nFinalizing... \n");

/*************************************************************************
* Очистить память, выделенную под информацию об адаптерах сканеров *
*************************************************************************/
free_adaptersInfo:
free(adaptersInfo);

/*************************************************************************
* Деинициализировать биометрические функции *
*************************************************************************/
finalize_bio:
rv = functionListBio->C_BIO_Finalize(NULL_PTR);
CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

/*************************************************************************
* Деинициализировать библиотеку *
*************************************************************************/
finalize_pkcs11:
rv = functionList->C_Finalize(NULL_PTR);
CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

/*************************************************************************
* Выгрузить библиотеку из памяти *
*************************************************************************/
unload_pkcs11:
CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
if (errorCode) {
printf("\n\nSome error occurred. Sample failed.\n");
} else {
printf("\n\nSample has been completed successfully.\n");
}

return errorCode;
}

Получение cписка доступных сканеров

Файл CBioListScanners.c
#include <BioCommon.h>

int main(void) {
    HMODULE module; // Дескриптор загруженной библиотеки PKCS#11

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_BIO_SCANNER_INFO_PTR scannersInfo; // Массив информации о сканерах
    CK_ULONG scannersInfoCount;           // Размер массива информации о сканерах

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11           *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                                *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции           *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать биометрический функционал                           *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    /*************************************************************************
     * Получить информацию о сканерах                                        *
     *************************************************************************/
    rv = functionListBio->C_BIO_ListScanners(NULL, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), finalize_bio);

    if (scannersInfoCount == 0) {
        printf("\nNo scanners available!\n\n");
        goto finalize_bio;
    }

    scannersInfo = (CK_BIO_SCANNER_INFO_PTR)malloc(scannersInfoCount * sizeof(CK_BIO_SCANNER_INFO));
    CHECK(" Memory allocation for scanners info", scannersInfo != NULL, finalize_bio);

    rv = functionListBio->C_BIO_ListScanners(scannersInfo, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), free_scannersInfo);

    /*************************************************************************
     * Вывести информацию о сканерах                                        *
     *************************************************************************/
    printf("\n");
    for (CK_ULONG i = 0; i < scannersInfoCount; ++i) {
        printf("%3lu. id:%3lu (%s) \n", i + 1, scannersInfo[i].id, scannersInfo[i].adapterName);
    }

    printf("\n");

    /*************************************************************************
     * Выставить признак успешного завершения программы                     *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под информацию о сканерах                 *
     *************************************************************************/
free_scannersInfo:
    free(scannersInfo);

    /*************************************************************************
     * Деинициализировать биометрический функционал                         *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}

Установка сканера по умолчанию

Файл CBioSetDefaultScanner.c
#include <BioCommon.h>

int main(void) {
    HMODULE module; // Дескриптор загруженной библиотеки PKCS#11

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_BIO_SCANNER_INFO_PTR scannersInfo; // Массив информации о сканерах
    CK_ULONG scannersInfoCount;           // Размер массива информации о сканерах

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11           *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                          *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                               *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать биометрический функционал                           *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    /*************************************************************************
     * Получить информацию о сканерах                                       *
     *************************************************************************/
    rv = functionListBio->C_BIO_ListScanners(NULL, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), finalize_bio);

    if (scannersInfoCount == 0) {
        printf("\nNo scanners available!\n\n");
        goto finalize_bio;
    }

    scannersInfo = (CK_BIO_SCANNER_INFO_PTR)malloc(scannersInfoCount * sizeof(CK_BIO_SCANNER_INFO));
    CHECK(" Memory allocation for scanners info", scannersInfo != NULL, finalize_bio);

    rv = functionListBio->C_BIO_ListScanners(scannersInfo, &scannersInfoCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), free_scannersInfo);

    /*************************************************************************
     * Вывести информацию о сканерах                                         *
     *************************************************************************/
    printf("\n");
    for (CK_ULONG i = 0; i < scannersInfoCount; ++i) {
        printf("%3lu. id:%3lu (%s) \n", i + 1, scannersInfo[i].id, scannersInfo[i].adapterName);
    }
    printf("\n");

    /*************************************************************************
     * Задать сканер по умолчанию                                            *
     *************************************************************************/
    int scannerNumber = 0;
    printf("\nPrint scanner number to set it default (or 0 reset default) ->");
    scanf("%d", &scannerNumber);
    if (scannerNumber < 0 || scannerNumber > (int)(scannersInfoCount)) {
        printf("Invalid scanner number!\n");
        goto free_scannersInfo;
    }

    if (scannerNumber == 0) {
        rv = functionListBio->C_BIO_SetDefaultScanner(NULL_PTR);
    } else {
        rv = functionListBio->C_BIO_SetDefaultScanner(&scannersInfo[scannerNumber - 1]);
    }
    CHECK_AND_LOG(" C_BIO_SetDefaultScanner", rv == CKR_OK, rvToStr(rv), free_scannersInfo);

    /*************************************************************************
     * Выставить признак успешного завершения программы                     *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11       *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную информацию об адаптерах сканеров          *
     *************************************************************************/
free_scannersInfo:
    free(scannersInfo);

    /*************************************************************************
     * Деинициализировать биометрический функционал                          *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}

Помещение отпечатка пальца на Рутокен

Устройство должно поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.


Файл CBioSetFingerprint.c
#include <BioCommon.h>

int main(void) {

    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии
    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList
    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO

    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio
    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве
    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11

    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                  *
     *************************************************************************/

    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/

    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/

    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на             *
     * биометрические функции                                                *
     *************************************************************************/

    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/

    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);
    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                      *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);
    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                           *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Администратора                              *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);

    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Инициализировать биометрический функционал                           *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Проверить наличие сканеров для начала работы                          *
     *************************************************************************/

    CK_ULONG scannersCount = 0;
    rv = functionListBio->C_BIO_ListScanners(NULL, &scannersCount);
    CHECK_AND_LOG(" C_BIO_ListScanners", rv == CKR_OK, rvToStr(rv), finalize_bio);

    if (scannersCount == 0) {
        printf("\n\nCan't set fingerprint without scanner. Sample will be finished.\n\n");
        goto finalize_bio;
    }

    /*************************************************************************
     * Получить информацию об отпечатке                                      *
     *************************************************************************/
    CK_BIO_FINGERPRINT_INFO fpInfo;
    CK_ULONG fpCount;
    rv = functionListBio->C_BIO_GetFingerprintInfo(session, &fpInfo, NULL, &fpCount);

    if (rv != CKR_BIO_FINGERPRINT_NOT_FOUND) {
        printf("\n\nUpdating fingerprint\nAuthentication needed\n\n");
        rv = functionListBio->C_BIO_Authenticate(session, 0, 0, 0, 0);
        CHECK_AND_LOG(" C_BIO_Authenticate", rv == CKR_OK, rvToStr(rv), finalize_bio);
    } else {
        printf("\n\nCreating new fingerprint \n\n");
    }

    /*************************************************************************
     * Создать или обновить отпечаток                                       *
     *************************************************************************/
    CK_BIO_FINGERPRINT_SCAN_PARAMS scanParams[] = {
        { CK_BIO_FT_LEFT_THUMB, 4 },
        { CK_BIO_FT_LEFT_INDEX, 4 },
        { CK_BIO_FT_LEFT_MIDDLE, 4 },
    };

    CK_ULONG scanParamsCount = sizeof(scanParams) / sizeof(CK_BIO_FINGERPRINT_SCAN_PARAMS);
    CK_BIO_FINGERPRINT_SCAN_STATUS_PTR status = (CK_BIO_FINGERPRINT_SCAN_STATUS_PTR)
malloc(scanParamsCount * sizeof(CK_BIO_FINGERPRINT_SCAN_STATUS));

    CHECK(" Memory allocation for scan status", status != NULL, finalize_bio);
    CK_ULONG statusCount = scanParamsCount;
    CK_BIO_FINGERPRINT_TYPE nextToScan;

    rv = functionListBio->C_BIO_SetFingerprintInit(session, scanParams, scanParamsCount, &nextToScan);
    CHECK_AND_LOG(" C_BIO_SetFingerprintInit", rv == CKR_OK, rvToStr(rv), free_scanStatus);

    while (1) {
        rv = functionListBio->C_BIO_SetFingerprintStatus(session, status, &statusCount);
        CHECK_AND_LOG(" C_BIO_SetFingerprintStatus", rv == CKR_OK, rvToStr(rv), free_scanStatus);
        printf("\nStatus:\n");
        for (size_t i = 0; i < statusCount; ++i) {
            printf("\nType %s: %lu / %lu \n", fingerprintTypeToString(status[i].type),
status[i].currentScansCount, status[i].targetScansCount);
        }

        if (nextToScan == CK_BIO_FT_UNKNOWN) {
            break;
        }
        printf("\nNext: %s \n", fingerprintTypeToString(nextToScan));
        rv = functionListBio->C_BIO_SetFingerprintScan(session, 0, &nextToScan);

        if (rv == CKR_OK) {
            printf("Successfully scanned\n");
        } else if (rv == CKR_BIO_UNACCEPTABLE_FINGERPRINT) {
            printf("Fingerprint not recognized. Try again\n");
        } else {
            printf("C_BIO_SetFingerprintScan failed");
            goto free_scanStatus;
        }
    }

    CK_ULONG fingerprintId = 0;
    rv = functionListBio->C_BIO_SetFingerprintFinal(session, &fingerprintId);
    CHECK_AND_LOG(" C_BIO_SetFingerprintFinal", rv == CKR_OK, rvToStr(rv), free_scanStatus);

    printf("\n\nFingerprint was set correctly, fingerprint id: %lu\n", fingerprintId);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11       *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под параметры отпечатков                 *
     *************************************************************************/

free_scanStatus:
    free(status);

    /*************************************************************************
     * Деинициализировать биометрический функционал                          *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/

    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                      *
     *************************************************************************/

close_session:
    rv = functionList->C_CloseSession(session);
    CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                      *
     *************************************************************************/
free_slots:
    free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                        *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }
    return errorCode;
}

Получение информации об отпечатке пальца

Устройство должно:

  1. Поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.
  2. Содержать объект набора отпечатков пальцев. Создание объекта описано в примере BioInitFingerprint.c.
Файл CBioGetFingerprintInfo.c
#include <BioCommon.h>

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_BIO_FINGERPRINT_INFO fingerprintInfo;   // информация об отпечатке
    CK_BIO_FINGERPRINT_SCAN_PARAMS_PTR params; // параметры скана отпечатка
    CK_ULONG paramsCount; // количество параметров скана отпечатка

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11            *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                               *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                  *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                      *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                           *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Пользователя                                 *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_USER, USER_PIN, USER_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Инициализировать биометрический функционал                            *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Получить информацию об отпечатке                                      *
     *************************************************************************/
    rv = functionListBio->C_BIO_GetFingerprintInfo(session, &fingerprintInfo, NULL, &paramsCount);
    CHECK_AND_LOG(" C_BIO_GetFingerprintInfo", rv == CKR_OK, rvToStr(rv), finalize_bio);
    CHECK_AND_LOG(" Got fingerprints count", paramsCount != 0, "", finalize_bio);

    params =
(CK_BIO_FINGERPRINT_SCAN_PARAMS_PTR)malloc(paramsCount * sizeof(CK_BIO_FINGERPRINT_SCAN_PARAMS));
    CHECK(" Memory allocation for fingerprint params", params != NULL, finalize_bio);

    rv = functionListBio->C_BIO_GetFingerprintInfo(session, &fingerprintInfo, params, &paramsCount);
    CHECK_AND_LOG(" C_BIO_GetFingerprintInfo", rv == CKR_OK, rvToStr(rv), free_params);

    /*************************************************************************
     * Вывести информацию об отпечатке                                       *
     *************************************************************************/
    printf(
        "\n\nGot fingerprint info:\n"
        "fingerprintId: %lu\nretryCountLeft: %lu\nmaxRetryCount: %lu\n"
        "type:%lu\n",
        fingerprintInfo.fingerprintId, fingerprintInfo.retryCountLeft, fingerprintInfo.maxRetryCount,
        fingerprintInfo.type);

    for (size_t i = 0; i < paramsCount; i++) {
        printf("finger %zu / %lu: type: %s, targetScansCount: %lu\n", (i + 1), paramsCount,
               fingerprintTypeToString(params[i].type), params[i].targetScansCount);
    }

    /*************************************************************************
     * Выставить признак успешного завершения программы                     *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11        *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Очистить память, выделенную под параметры отпечатков                  *
     *************************************************************************/
free_params:
    free(params);

    /*************************************************************************
     * Деинициализировать биометрический функционал                           *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

logout:
    /*************************************************************************
     * Сбросить права доступа                                                 *
     *************************************************************************/
    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                        *
     *************************************************************************/
close_session:
    rv = functionList->C_CloseSession(session);
    CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                      *
     *************************************************************************/
free_slots:
    free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                          *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                         *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}

Разблокировка использования отпечатков пальцев

Устройство должно поддерживать биометрическую аутентификацию. Проверить этот функционал можно как в примере BioCheckToken.c.

Файл  CBioUnblockFingerprint.c
#include <BioCommon.h>

int main(void) {
    HMODULE module;            // Дескриптор загруженной библиотеки PKCS#11
    CK_SESSION_HANDLE session; // Дескриптор открытой сессии

    CK_FUNCTION_LIST_PTR functionList;    // Указатель на список функций PKCS#11,
                                          // хранящийся в структуре CK_FUNCTION_LIST
    CK_C_GetFunctionList getFunctionList; // Указатель на функцию C_GetFunctionList

    CK_FUNCTION_LIST_BIO_PTR functionListBio; // Указатель на список биометрических функций PKCS#11,
                                              // хранящийся в структуре CK_FUNCTION_LIST_BIO
    CK_C_BIO_GetFunctionListBio getFunctionListBio; // Указатель на функцию C_BIO_GetFunctionListBio

    CK_SLOT_ID_PTR slots; // Массив идентификаторов слотов
    CK_ULONG slotCount;   // Количество идентификаторов слотов в массиве

    CK_RV rv; // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1; // Флаг ошибки

    /*************************************************************************
     * Выполнить действия для начала работы с библиотекой PKCS#11           *
     *************************************************************************/
    printf("Initialization...\n");

    /*************************************************************************
     * Загрузить библиотеку                                                 *
     *************************************************************************/
    module = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на функции     *
     *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на функции                           *
     *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить адрес функции запроса структуры с указателями на            *
     * биометрические функции                                               *
     *************************************************************************/
    getFunctionListBio = (CK_C_BIO_GetFunctionListBio)GetProcAddress(module, "C_BIO_GetFunctionListBio");
    CHECK(" GetProcAddress", getFunctionListBio != NULL, unload_pkcs11);

    /*************************************************************************
     * Получить структуру с указателями на биометрические функции            *
     *************************************************************************/
    rv = getFunctionListBio(&functionListBio);
    CHECK_AND_LOG(" Get biometric function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Инициализировать библиотеку                                           *
     *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
     * Получить количество слотов c подключенными токенами                   *
     *************************************************************************/
    rv = functionList->C_GetSlotList(CK_TRUE, NULL_PTR, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList (number of slots)", rv == CKR_OK, rvToStr(rv), finalize_pkcs11);

    CHECK_AND_LOG(" Checking available tokens", slotCount > 0, " No tokens available", finalize_pkcs11);

    /*************************************************************************
     * Получить список слотов c подключенными токенами                       *
     *************************************************************************/
    slots = (CK_SLOT_ID_PTR)malloc(slotCount * sizeof(CK_SLOT_ID));
    CHECK(" Memory allocation for slots", slots != NULL, finalize_pkcs11);

    rv = functionList->C_GetSlotList(CK_TRUE, slots, &slotCount);
    CHECK_AND_LOG(" C_GetSlotList", rv == CKR_OK, rvToStr(rv), free_slots);
    printf(" Slots available: %d\n", (int)slotCount);

    /*************************************************************************
     * Открыть RW сессию в первом доступном слоте                           *
     *************************************************************************/
    rv = functionList->C_OpenSession(slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
    CHECK_AND_LOG(" C_OpenSession", rv == CKR_OK, rvToStr(rv), close_session);

    /*************************************************************************
     * Выполнить аутентификацию Администратора                              *
     *************************************************************************/
    rv = functionList->C_Login(session, CKU_SO, SO_PIN, SO_PIN_LEN);
    CHECK_AND_LOG(" C_Login", rv == CKR_OK, rvToStr(rv), close_session);
    printf("Initialization has been completed successfully.\n");

    /*************************************************************************
     * Инициализировать биометрический функционал                            *
     *************************************************************************/
    rv = functionListBio->C_BIO_Initialize(0);
    CHECK_AND_LOG(" C_BIO_Initialize", rv == CKR_OK, rvToStr(rv), logout);

    /*************************************************************************
     * Разблокировать отпечаток                                             *
     *************************************************************************/

    rv = functionListBio->C_BIO_UnblockFingerprint(session);
    CHECK_AND_LOG(" C_BIO_UnblockFingerprint", rv == CKR_OK, rvToStr(rv), finalize_bio);

    /*************************************************************************
     * Выставить признак успешного завершения программы                      *
     *************************************************************************/
    errorCode = 0;

    /*************************************************************************
     * Выполнить действия для завершения работы с библиотекой PKCS#11       *
     *************************************************************************/
    printf("\nFinalizing... \n");

    /*************************************************************************
     * Деинициализировать биометрический функционал                         *
     *************************************************************************/
finalize_bio:
    rv = functionListBio->C_BIO_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_BIO_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

logout:
    /*************************************************************************
     * Сбросить права доступа                                                *
     *************************************************************************/
    rv = functionList->C_Logout(session);
    CHECK_RELEASE_AND_LOG(" C_Logout", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Закрыть открытую сессию в слоте                                       *
     *************************************************************************/
close_session:
    rv = functionList->C_CloseSession(session);
    CHECK_RELEASE_AND_LOG(" C_CloseSession", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Очистить память, выделенную под слоты                      *
     *************************************************************************/
free_slots:
    free(slots);

    /*************************************************************************
     * Деинициализировать библиотеку                                        *
     *************************************************************************/
finalize_pkcs11:
    rv = functionList->C_Finalize(NULL_PTR);
    CHECK_RELEASE_AND_LOG(" C_Finalize", rv == CKR_OK, rvToStr(rv), errorCode);

    /*************************************************************************
     * Выгрузить библиотеку из памяти                                       *
     *************************************************************************/
unload_pkcs11:
    CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);

exit:
    if (errorCode) {
        printf("\n\nSome error occurred. Sample failed.\n");
    } else {
        printf("\n\nSample has been completed successfully.\n");
    }

    return errorCode;
}
  • No labels