Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Введение

Предназначение устройств Рутокен

Рутокен

Рутокен Lite

Рутокен ЭЦП

Рутокен PINPad

Рутокен PINPad представляет собой решение класса TrustScreen, которое позволяет визуализировать подписываемый документ на экране доверенного устройства перед наложением электронной подписи. Устройство  Устройство позволяет реализовать следующие незаменимые в PKI-инфраструктуре возможности: 

  • Формировать запросы на сертификат в формате PKCS#10 для неизвлекаемых ключей электронной подписи ГОСТ Р 34.10-2001 с возможностью визуализации и подтверждения на устройстве;
  • Подписывать и шифровать данные в формате CMS с использованием алгоритмов ГОСТ Р 34.10-2001, ГОСТ Р 34.11-94 и ГОСТ 28147-89, схемы VKO;
  • Хранить и использовать сертификаты открытого ключа ГОСТ Р 34.10-2001 в формате X.509.

Кроме того, Рутокен  Рутокен PINPad поддерживает национальные стандарты в полном объеме:

  • алгоритмы  ГОСТ алгоритмы  ГОСТ Р 34.10-2012 и ГОСТ Р 34.10-2001: генерация ключевых пар с проверкой качества, импорт ключевых пар, формирование и проверка электронной подписи, срок действия закрытых ключей до 3-х лет.
  • алгоритмы  ГОСТ алгоритмы  ГОСТ Р 34.11-2012 и ГОСТ Р 34.11-94: вычисление значения хеш-функции данных, в том числе с возможностью последующего формирования электронной подписи.
  • алгоритм ГОСТ 28147-89: генерация и импорт ключей шифрования, шифрование данных в режимах простой замены, гаммирования и гаммирования с обратной связью, вычисление и проверка криптографической контрольной суммы данных (имитовставки ГОСТ).
  • выработка сессионных ключей (ключей парной связи): по схеме VKO GOST R 34.10-2001 (RFC 4357), расшифрование по схеме EC El-Gamal.
  • генерация последовательности случайных чисел требуемой длины.

Начало работы

Подключение библиотеки

Для работы с устройствами Рутокен по стандарту PKCS#11 приложение предварительно должно динамически загрузить библиотеку, реализующую интерфейс стандарта. Рутокен SDK предоставляет две библиотеки rtPKCS11.dll и rtPKCS11ECP.dll, подробнее об особенностях выбора и использования которых можно ознакомиться в разделе Использование библиотек rtPKCS11 и rtPKCS11ECP. Основная разница заключается в том, что российские алгоритмы доступны в библиотеке rtPKCS11ECP.dll, а зарубежные - в rtPKCS11.dll.

Генерация ключевой пары 

Атрибуты ключевых объектов

После загрузки библиотеки нужно получить адрес экспортируемой библиотекой функции C_GetFunctionList и вызвать ее для получения списка функций PKCS#11. Теперь все готово для работы с библиотекой.

Для работы с функциями расширения необходимо получить адрес функции CK_C_EX_GetFunctionListExtended и вызвать ее для получения списка функций расширения PKCS#11.

После работы с библиотекой ее нужно выгрузить из памяти.

Code Block
languagecpp
titleЗагрузка библиотеки и списка функций PKCS#11
/* Имя библиотеки PKCS#11 */
#ifdef _WIN32
/* Библиотека для Рутокен S, Рутокен Lite и Рутокен ЭЦП, поддерживает только алгоритмы RSA */
	#define PKCS11_LIBRARY_NAME         "rtPKCS11.dll" 
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11ECP_LIBRARY_NAME      "rtPKCS11ECP.dll"
#endif 
#ifdef __unix__
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11_LIBRARY_NAME         "librtpkcs11ecp.so"
	#define PKCS11ECP_LIBRARY_NAME      "librtpkcs11ecp.so"
#endif 	
#ifdef __APPLE__
/* Библиотека для Рутокен Lite, Рутокен ЭЦП, Рутокен PINPad, поддерживает алгоритмы ГОСТ и RSA */
	#define PKCS11_LIBRARY_NAME         "librtpkcs11ecp.dylib"
	#define PKCS11ECP_LIBRARY_NAME      "librtpkcs11ecp.dylib"
#endif 	

HMODULE hModule = NULL_PTR;                                     // Хэндл загруженной библиотеки PKCS#11
CK_FUNCTION_LIST_PTR pFunctionList = NULL_PTR;                  // Указатель на список функций PKCS#11, хранящийся в структуре CK_FUNCTION_LIST
CK_C_GetFunctionList pfGetFunctionList = NULL_PTR;              // Указатель на функцию C_GetFunctionList
CK_RV rv = CKR_OK;                                              // Вспомогательная переменная для хранения кода возврата
 
while (TRUE)
{
	/* Загрузить библиотеку */
	printf("Loading library %s", PKCS11ECP_LIBRARY_NAME);
	hModule = LoadLibrary(PKCS11ECP_LIBRARY_NAME);
	if (hModule == NULL_PTR)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");

	/* Получить адрес функции запроса структуры с указателями на функции */	
	printf("Getting GetFunctionList function");
	pfGetFunctionList = (CK_C_GetFunctionList)GetProcAddress(hModule, "C_GetFunctionList");
	if (pfGetFunctionList == NULL_PTR)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
 
	/* Получить структуру с указателями на функции */
	printf("Getting function list");
	rv = pfGetFunctionList(&pFunctionList);
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
	...
	break;
}
 
/* Выгрузить библиотеку из памяти */
if (hModule)
{
	printf("Unloading library");
	if (FreeLibrary(hModule) != TRUE)
		printf(" -> Failed\n");
	else
		printf(" -> OK\n");
	hModule = NULL_PTR;
}

Инициализация библиотеки

После загрузки библиотеки нужно ее инициализировать вызовом функции C_Initialize. Параметр NULL при вызове данной функции означает, что функции библиотеки не будут вызываться из нескольких потоков, в противном случае в параметре должен быть передан указатель на структуру типа CK_INITIALIZE_ARGS.

Для завершения работы с библиотекой ее нужно деинициализировать вызовом функции C_Finalize().

Code Block
languagecpp
titleИнициализация библиотеки
/* Инициализировать библиотеку */
printf("Initializing library");
rv = pFunctionList->C_Initialize(NULL_PTR);
if (rv != CKR_OK)
	printf(" -> Failed\n");
printf(" -> OK\n");
...
 
/* Деинициализировать библиотеку */
if (pFunctionList)
{
	printf("Finalizing library");
	rvTemp = pFunctionList->C_Finalize(NULL_PTR);
	if (rvTemp != CKR_OK)
		printf(" -> Failed\n");
	else
		printf(" -> OK\n");
	pFunctionList = NULL_PTR;
}

Определение подключенных устройств

Доступ к каждому подключенному устройству осуществляется с помощью идентификатора слота, к которому оно подключено. Для получения списка всех слотов предназначена функция C_GetSlotList. Значение первого параметра указывает, должен ли список включать слоты только с подключенным токенами (CK_TRUE) или все слоты (CK_FALSE). 

Code Block
languagecpp
titleПолучение списка токенов
CK_SLOT_ID_PTR aSlots = NULL_PTR;           // Указатель на массив идентификаторов слотов
CK_ULONG ulSlotCount = 0;                   // Количество идентификаторов слотов в массиве
 
while(TRUE)
{
...
	/* Получить количество слотов c подключенными токенами */
	printf(" Getting number of connected slots");
	rv = pFunctionList->C_GetSlotList(CK_TRUE, NULL_PTR, &ulSlotCount);
	if (rv != CKR_OK)
	{
		printf(" -> Failed\n");
		break;
	}
	printf(" -> OK\n");
 
	aSlots = (CK_SLOT_ID*)malloc(ulSlotCount * sizeof(CK_SLOT_ID));
	memset(aSlots, 0, (ulSlotCount * sizeof(CK_SLOT_ID)));


	/* Получить список слотов c подключенными токенами */
	printf(" Getting list of connected slots");
	rv = pFunctionList->C_GetSlotList(CK_TRUE,	aSlots, &ulSlotCount);
	if (rv != CKR_OK)
	{
		printf(" -> Failed %X\n", (int)rv);
		break;
	}
	printf(" -> OK\n");

	printf(" Slots available: 0x%8.8X\n", (int)ulSlotCount);
	...
	break;
}
 
if (aSlots)
{
	free(aSlots);
	aSlots = NULL_PTR;
}

Для получения актуальной информации о состоянии конкретного слота вызывается функция C_GetSlotInfo, в которую передается идентификатор слота. Ее вызов запускает обновление информации обо всех слотах. Если токен извлечь из разъема и затем снова вставить в тот же самый разъем, то он может подключиться к любому свободному слоту, а не обязательно к тому же самому.

Мониторинг событий в слоте

Для мониторинга событий извлечения и подключения токенов для всех слотов используется функция C_WaitForSlotEvent, запущенная в отдельном потоке.

При вызове C_WaitForSlotEvent с флагом CKF_DONT_BLOCK функция возвращает код CKR_NO_EVENT при отсутствии событий или код CKR_OK при его наличии (вместе с идентификатором соответствующего событию слота).

При вызове C_WaitForSlotEvent с флагом 0 выполнение функции блокируется до возникновения события и функция возвращает код CKR_OK и номер соответствующего слота.

Code Block
languagecpp
titleМониторинг событий в слотах
 

Определение типа устройств


Генерация ключевой пары

Атрибуты ключевых объектов

Все поддерживаемые устройствами Рутокен атрибуты объектов представлены в разделе Объекты PKCS #11.

Атрибуты ключевых объектов Рутокен PINPad 

Рутокен Рутокен PINPad имеет два специфических атрибута закрытого ключа, которые влияют на поведение устройства при устройства при осуществлении криптографических операций с использованием такого ключа: CKA_VENDOR_KEY_CONFIRM_OP и CKA_VENDOR_KEY_PIN_ENTER. Оба атрибута присваиваются закрытому ключу при генерации ключевой пары соответственно указанным в шаблоне значениям и поэтому не могут быть изменены после генерации. Помимо закрытого ключа, эти атрибуты могут быть присвоены также секретному ключу.

Если ключ был создан с флагом визуализации CKA_VENDOR_KEY_CONFIRM_OP, то данные, которые подписываются с помощью такого ключа, перед подписью будут показаны на экране устройства и для их подписи потребуется подтверждение пользователя в виде нажатия специальной кнопки на тачскрине устройства. 

Если ключ был создан с флагом повышенной защиты CKA_VENDOR_KEY_PIN_ENTER, то для подписи таким ключом перед операцией потребуется операцией потребуется ввести PIN-код на тачскрине устройства.  

Примеры шаблонов ключей

Ниже представлены примеры шаблонов закрытого и открытого ключа ГОСТ Р 34.10-2001 с пояснениями.

Code Block
languagecpp
titleШаблон закрытого ключа ГОСТ Р 34.10-2001
CK_OBJECT_CLASS     	ocPrivKey       	 	= CKO_PRIVATE_KEY;
CK_UTF8CHAR      	PrivKeyLabel[]  	= {"GOST Private Key"}; 
CK_BYTE          		KeyPairID[]     	= {"GOST keypair"}; 
CK_KEY_TYPE         KeyType		KeyType 		= CKK_GOSTR3410;  	// или CKK_GOSTR3410_512 для ключа длиной 512 битбит 
CK_BBOOL    		bTrue           			= CK_TRUE; 
CK_BYTE 	GOST3410_params_oid		GOST3410params[]  	= { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }; // Параметры алгоритма ГОСТ Р 34.10-2001  
 
CK_ATTRIBUTE GOST34_10_2001PrivateKey[] =
 { 
	{ CKA_CLASS, &ocPrivKey, sizeof(ocPrivKey)},                    					// Объект закрытого ключаключа 
	{ CKA_LABEL, &PrivKeyLabel, sizeof(PrivKeyLabel) - 1},      			// Метка ключаключа 
	{ CKA_ID, &KeyPairID, sizeof(KeyPairID) - 1},         					// Идентификатор ключевой пары #1 (должен совпадать у открытого и закрытого ключей) 
	{ CKA_KEY_TYPE, &KeyType, sizeof(ktGOSTKeyType)},   					// Тип ключаключа 
	{ CKA_DECRYPT, &bTrue, sizeof(bTrue)},                          							// Ключ предназначен для расшифрованиярасшифрования 
	{ CKA_TOKEN, &bTrue, sizeof(bTrue)},                            							// Ключ является объектом токенатокена 
	{ CKA_PRIVATE, &bTrue, sizeof(bTrue)},                          							// Ключ доступен только после авторизации на токенетокене 
	{ CKA_DERIVE, &bTrue, sizeof(bTrue)},                           							// Ключ поддерживает деривацию (из него могут быть получены другие ключи) 
	{ CKA_VENDOR_KEY_CONFIRM_OP, &bTrue, sizeof(bTrue) },           			// Операция подписи требует подтверждения на PINPadPINPad 
	{ CKA_VENDOR_KEY_PIN_ENTER, &bTrue, sizeof(bTrue) },            			// Операция подписи требует ввода PIN-кода на PINPadPINPad 
	{ CKA_GOSTR3410_PARAMS, GOST3410params, sizeof(GOST3410params)} // Параметры алгоритмаалгоритма 
};
Code Block
languagecpp
titleШаблон открытого ключа ГОСТ Р 34.10-2001
CK_OBJECT_CLASS     ocPubKey        		= CKO_PUBLIC_KEY; 
CK_UTF8CHAR      	PubKeyLabel[]   	= {"GOST Public Key"}; 
CK_BYTE          		KeyPairID[]     	= {"GOST keypair"}; 
CK_KEY_TYPE         KeyType	KeyType 			= CKK_GOSTR3410;
CK_BBOOL // или  		bTrue           CKK_GOSTR3410_512 для ключа длиной 512 бит 
CK_BBOOL 		bTrue 			= CK_TRUE; 
CK_BBOOL    		bFalse 			= CK_FALSE; 
CK_BYTE 			GOST3410params[]	= { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }; // Параметры алгоритма ГОСТ Р 34.10-20012001 
CK_BYTE 			GOST3411params[]	= { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 }; // Параметры алгоритма ГОСТ Р 34.11-1994   
 
CK_ATTRIBUTE GOST34_10_2001PublicKey[] =
 {
	{ CKA_CLASS, &ocPubKey, sizeof(ocPubKey)},                      						// Объект открытого ключа ключа 
	{ CKA_LABEL, &PubKeyLabel, sizeof(PubKeyLabel)-1},        				// Метка ключаключа 
	{ CKA_ID, &KeyPairID, sizeof(KeyPairID)-1},        					// Идентификатор ключевой парыпары 
	{ CKA_KEY_TYPE, &KeyType, sizeof(KeyType)},   					// Тип ключаключа 
	{ CKA_ENCRYPT, &bTrue, sizeof(bTrue)},                          							// Ключ предназначен для зашифрованиязашифрования 
	{ CKA_TOKEN, &bTrue, sizeof(bTrue)},                            							// Ключ является объектом токенатокена 
	{ CKA_PRIVATE, &bFalse, sizeof(bFalse)},                        						// Ключ доступен без авторизации на токенетокене 
	{ CKA_DERIVE, &bTrue, sizeof(bTrue)},                           							// Ключ поддерживает деривацию (из него могут быть получены другие ключи).
	{ CKA_GOSTR3410_PARAMS, GOST3410params, sizeof(GOST3410params)},// Параметры алгоритмаалгоритма 
	{ CKA_GOSTR3411_PARAMS, GOST3411params, sizeof(GOST3411params)} // Параметры алгоритмаалгоритма 
};

Пример использования генерации ключей

Поддерживаемые механизмы генерации ключей

...

Любой сценарий начинается с определения всех подключенных к компьютеру устройств Рутокен PINPad. 

При этом возвращается список идентификаторов подключенных устройств. Идентификатор представляет собой число, связанное с номером слота, в который подключено устройство. При повторном перечислении это число может отличаться для одного и того устройства.

Рутокен Плагин определяет все подключенные к компьютеру  UBS-устройства Рутокен ЭЦП, Рутокен WEB и Рутокен PINPad. Поэтому следующим шагом следует определить тип устройства.

Определение типа устройства

Для определения типа устройства следует использовать функцию getDeviceInfo с параметром TOKEN_INFO_DEVICE_TYPE. Значение этой константы содержится в объекте плагина. Для Рутокен PINPad результатом вызова данной функции будет TOKEN_TYPE_RUTOKEN_PINPAD_2, числовая константа, которая так же находится в объекте плагин.

Чтобы Рутокен PINPad распознал данные, они должны быть отправлены на подпись в специальном формате. 

...