...
Code Block | ||||
---|---|---|---|---|
| ||||
CK_SESSION_HANDLE hSession = NULL_PTR; // Хэндл открытой сессии ... /* Открыть RW сессию в первом доступном слоте */ printf("Opening Session"); rv = pFunctionList->C_OpenSession(aSlots[0], // Идентификатор слота CKF_SERIAL_SESSION | CKF_RW_SESSION, // Флаги сессии NULL_PTR, NULL_PTR, &hSession); // Хэндл сессии if (rv != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); ... /* Закрыть все открытые сессии в слоте */ printf("C_CloseAllSession"); rv = pFunctionList->C_CloseAllSessions(aSlots[0]); if (rvTemp != CKR_OK) printf(" -> Failed\n"); else printf(" -> OK\n"); hSession = NULL_PTR; |
...
Получение и
...
сброс прав доступа
В PKCS#11 доступны две ролиТипы пользователя: CKU_USER -- пользователь Рутокен, CKU_SO -- администратор Рутокен.
...
Code Block | ||||
---|---|---|---|---|
| ||||
CK_OBJECT_CLASS ocPubKey = CKO_PUBLIC_KEY;
CK_UTF8CHAR PubKeyLabel[] = {"GOST Public Key"};
CK_BYTE KeyPairID[] = {"GOST keypair"};
CK_KEY_TYPE KeyType = CKK_GOSTR3410;
CK_BBOOL bTrue = CK_TRUE;
CK_BBOOL bFalse = CK_FALSE;
/* Набор параметров КриптоПро A алгоритма ГОСТ Р 34.10-2001 */
CK_BYTE GOST3410params[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }; // Параметры алгоритма ГОСТ Р 34.10-2001
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)} // Параметры алгоритма
}; |
...
Code Block | ||||
---|---|---|---|---|
| ||||
CK_OBJECT_CLASS ocPubKey = CKO_SECRET_KEY; CK_UTF8CHAR SecKeyLabel[] = {"GOST Secret Key"}; CK_BYTE SecKeyID[] = {"GOST Secret Key"}; CK_KEY_TYPE KeyType = CKK_GOST28147; CK_BBOOL bTrue = CK_TRUE; CK_BBOOL bFalse = CK_FALSE; /* Набор параметров КриптоПро A алгоритма ГОСТ 28147-89 */ CK_BYTE GOST28147params[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 0x01 }; // Параметры алгоритма ГОСТ 28147-89 CK_ATTRIBUTE attrGOST28147_89SecKey[] = { { CKA_CLASS, &ocSeckey, sizeof(ocSeckey)}, // Объект секретного ключа ГОСТ 28147-89 { CKA_LABEL, &SecKeyLabel, sizeof(SecKeyLabel) - 1}, // Метка ключа { CKA_ID, &SecKeyID, sizeof(SecKeyID) - 1}, // Идентификатор ключа { CKA_KEY_TYPE, &KeyType, sizeof(KeyType)}, // Тип ключа { CKA_ENCRYPT, &bTrue, sizeof(bTrue)}, // Ключ предназначен для зашифрования { CKA_DECRYPT, &bTrue, sizeof(bTrue)}, // Ключ предназначен для расшифрования { CKA_TOKEN, &bTrue, sizeof(bTrue)}, // Ключ является объектом токена { CKA_PRIVATE, &bFalse, sizeof(bFalse)}, // Ключ доступен без авторизации на токене { CKA_VENDOR_KEY_CONFIRM_OP, &bTrue, sizeof(bTrue) }, // Операция шифрования/расшифрования требует подтверждения на PINPad (только для Рутокен PINPad) { CKA_VENDOR_KEY_PIN_ENTER, &bTrue, sizeof(bTrue) }, // Операция шифрования/расшифрования требует ввода PIN-кода на PINPad (только для Рутокен PINPad) { CKA_GOST28147_PARAMS, GOST28147params, sizeof(GOST28147params)} // Параметры алгоритма }; |
...
Code Block | ||||
---|---|---|---|---|
| ||||
/* Данные для подписихеширования в виде двоичной строки */ CK_BYTE pbtData[] = { 0x3C, 0x21, 0x50, 0x49, 0x4E, 0x50, 0x41, 0x44, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x52, 0x55, 0x3E, 0x3C, 0x21, 0x3E, 0xED, 0xE5, 0xE2, 0xE8, 0xE4, 0xE8, 0xEC, 0xFB, 0xE9, 0x20, 0xF2, 0xE5, 0xEA }; while(TRUE) { ... /* Инициализировать операциюМеханизм хеширования */ printf("C_DigestInit"); rv = pFunctionList->C_DigestInit(hSession, &HashMech); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Определить размер хешированных данныхГОСТ Р 34.11-94 */ CK_MECHANISM HashMech = {CKM_GOSTR3411, NULL_PTR, 0}; CK_BYTE_PTR pbtHash = NULL_PTR; // Указатель на буфер для хешированных данных CK_ULONG ulHashSize = 0; // Размер буфера в байтах while(TRUE) { ... /* Инициализировать операцию хеширования */ printf("C_Digest step 1DigestInit"); rv = pFunctionList->C_DigestDigestInit( hSession, pbtData, ulData, pbtHash, &ulHashSize); if &HashMech); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtHash = (CK_BYTE*)malloc(ulHashSize); memset(pbtHash, 0, (ulHashSize * sizeof(CK_BYTE))); /* СформироватьОпределить хешразмер от исходныххешированных данных */ printf("C_Digest step 21"); rv = pFunctionList->C_Digest( hSession, pbtData, ulDataarraysize(pbtData), pbtHash, &ulHashSize); if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); break; } |
Подпись и проверка подписи
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы подписи:
CKM_GOSTR3410
подписи алгоритмом ГОСТ Р 34.10.2001,CKM_GOSTR3410_WITH_GOSTR3411
для совместного хеширования алгоритмомCKM_GOSTR3411
и подписи алгоритмом CKM_GOSTR3410,CKM_GOSTR3410_512
для подписи алгоритмом ГОСТ Р 34.10.2012 с длиной закрытого ключа 512 бит,CKM_GOSTR3410_WITH_GOSTR3411_12_256
для совместного хеширования алгоритмомCKM_GOSTR3411_12_256
и подписи на ключе длиной 256 бит,CKM_GOSTR3410_WITH_GOSTR3411_12_512
для совместного хеширования алгоритмомCKM_GOSTR3411_12_512
и подписи на ключе длиной 512 бит,CKM_RSA_PKCS
для подписи алгоритмом RSA.
Сырая подпись
Для подписи сырых данных служат функции C_SignInit()
и C_Sign()
. Сначала операцию подписи нужно инициализировать через C_SignInit()
, передав в нее идентификатор сессии, механизма и закрытого ключа. Затем размер буфера подписанных данных можно определить, вызвав C_Sign()
, и подписать данные, вызвав C_Sign()
второй раз.
При использовании совместных алгоритмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Sign() передается открытый текст для подписи, при использовании только алгоритма подписи (например, CKM_GOSTR3410
) -- уже прохешированные данные.
При использовании совместных алгоритмов хеширования и подписи в механизме должны быть заданы параметры алгоритма хеширования.
pbtHash = (CK_BYTE*)malloc(ulHashSize);
memset(pbtHash,
0,
(ulHashSize * sizeof(CK_BYTE)));
/* Сформировать хеш от исходных данных */
printf("C_Digest step 2");
rv = pFunctionList->C_Digest(hSession,
pbtData,
arraysize(pbtData),
pbtHash,
&ulHashSize);
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
break;
}
|
Подпись и проверка подписи
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы подписи:
CKM_GOSTR3410
подписи алгоритмом ГОСТ Р 34.10.2001,CKM_GOSTR3410_WITH_GOSTR3411
для совместного хеширования алгоритмомCKM_GOSTR3411
и подписи алгоритмом CKM_GOSTR3410,CKM_GOSTR3410_512
для подписи алгоритмом ГОСТ Р 34.10.2012 с длиной закрытого ключа 512 бит,CKM_GOSTR3410_WITH_GOSTR3411_12_256
для совместного хеширования алгоритмомCKM_GOSTR3411_12_256
и подписи на ключе длиной 256 бит,CKM_GOSTR3410_WITH_GOSTR3411_12_512
для совместного хеширования алгоритмомCKM_GOSTR3411_12_512
и подписи на ключе длиной 512 бит,CKM_RSA_PKCS
для подписи алгоритмом RSA.
Формат данных для подписи, отображаемый Рутокен PINPad
Если у закрытого ключа, которым подписываются данные, выставлен флаг визуализации, перед подписью Рутокен PINPad выведет на экран подписываемые данные для проверки и будет ожидать подтверждения или отмены операции. Чтобы Рутокен PINPad мог отобразить подписываемые данные, они должны иметь определенный формат:
Code Block | ||||
---|---|---|---|---|
| ||||
<!PINPADFILE RU> // обязательный признак строки, которая будет распознаваться Rutoken PINPad
<!>some text // текст, нераспознаваемый Rutoken PINPad
<N>some text // наименование поля
<V>some text // значение поля |
Подпись данных
Для вычисления отделяемой подписи сообщения служат функции C_SignInit()
и C_Sign()
. Сначала операцию подписи нужно инициализировать через C_SignInit()
, передав в нее идентификатор сессии, механизма и закрытого ключа. Затем размер буфера подписанных данных можно определить, вызвав C_Sign()
, и подписать данные, вызвав C_Sign()
второй раз.
При использовании совместных алгоритмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Sign()
передается открытый текст для подписи, при использовании только алгоритма подписи (например, CKM_GOSTR3410
) – уже прохешированные данные.
При использовании совместных алгоритмов хеширования и подписи в механизме должны быть заданы параметры алгоритма хеширования.
В качестве данных на подпись может быть передан запрос на сертификат, представленный в байт-коде.
Code Block | ||||
---|---|---|---|---|
| ||||
/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */
CK_MECHANISM SigVerMech = {CKM_GOSTR3410, NULL_PTR, 0};
/* Набор параметров КриптоПро алгоритма ГОСТ Р 34.11-1994 */
CK_BYTE GOST3411params[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 };
/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 с хешированием по алгоритму ГОСТ Р 34.11-94*/
CK_MECHANISM HashSigVerMech = {CKM_GOSTR3410_WITH_GOSTR3411, GOST3411params, sizeof(GOST3411params)};
CK_BYTE_PTR pbtSignature = NULL_PTR; // Указатель на буфер, содержащий подпись для исходных данных
CK_ULONG ulSignatureSize = 0; // Размер буфера, содержащего подпись для исходных данных, в байтах
while(TRUE)
{
...
/* Инициализировать операцию подписи данных */
printf("C_SignInit");
rv = pFunctionList->C_SignInit( hSession, // Хэндл сессии
&SigVerMech, // Механизм подписи
hPrivateKey ); // Хэндл закрытого ключа
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Определить размер подписанных данных */
printf("C_Sign step 1");
rv = pFunctionList->C_Sign( hSession, // Хэндл сессии
pbtHash, // Буфер с данными для подписи
ulHashSize, // Длина подписываемых данных
pbtSignature, // Буфер с подписанными данными
&ulSignatureSize); // Длина подписанных данных
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
pbtSignature = (CK_BYTE*)malloc(ulSignatureSize);
memset( pbtSignature,
0,
ulSignatureSize * sizeof(CK_BYTE));
/* Подписать исходные данные */
printf("C_Sign step 2");
rv = pFunctionList->C_Sign( hSession, // Хэндл сессии
pbHash, // Буфер с данными для подписи
ulHashSize, // Длина подписываемых данных
pbtSignature, // Буфер с подписанными данными
&ulSignatureSize); // Длина подписанных данных
if (rv != CKR_OK)
{
printf(" -> Failed\n");
break;
}
printf(" -> OK\n");
/* Распечатать буфер, содержащий подпись */
printf("Signature buffer is: \n");
for (i = 0;
i < ulSignatureSize;
i++)
{
printf("%02X ", pbtSignature[i]);
if ((i + 1) % 8 == 0)
printf("\n");
} |
Подпись данных в формате CMS (PKCS#7)
Для вычисления подписи в формате PKCS#7 существует функция C_EX_PKCS7Sign(), в которую сразу передаются все необходимые для операции данные. Для такой подписи необходимо наличие сертификата, которым будут подписываться данные.
После окончания работы с функцией необходимо освободить буфер, содержащий подпись, вызвав функцию C_EX_FreeBuffer().
Code Block | ||||
---|---|---|---|---|
| ||||
CK_OBJECT_HANDLE hCert; // Хэндл сертификата
...
/* Подпись | ||||
Code Block | ||||
| ||||
/* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2001 */ CK_MECHANISM SigVerMech = {CKM_GOSTR3410, NULL_PTR, 0}; while(TRUE) { ... /* Инициализировать операцию подписи данных */ printf("C_SignInit"); rv = pFunctionList->C_SignInit( hSession, // Хэндл сессии &SigVerMech, // Механизм подписи hPrivateKey ); // Хэндл закрытого ключа if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); /* Определить размер подписанных данных */ printf("C_Sign step 1PKCS7 Sign"); rv = pFunctionListpFunctionListEx->C_SignEX_PKCS7Sign( hSession, // Хэндл сессии pbHash pbtData, // Буфер с данными для подписи ulHashSize, arraysize(pbtData), // Размер Длинаданных подписываемыхдля данныхподписи pbtSignature hCert, // Буфер с подписанными данными Хэндл сертификата &ulSignatureSize); // Длина подписанных данных if (rv != CKR_OK) { printf(" -> Failed\n"); break; } printf(" -> OK\n"); pbtSignature = (CK_BYTE*)malloc(ulSignatureSize); memset( pbtSignature, 0, ulSignatureSize * sizeof(CK_BYTE)); /* Подписать исходные данные */ printf("C_Sign step 2"); rv = pFunctionList->C_Sign( hSession, &pbtSignature, // Буфер для подписанных данных &ulSignatureSize, // Размер подписанных данных hPrvKey, // Хэндл сессиизакрытого ключа, соответствующего сертификату pbHash NULL, // БуферУказатель сна даннымимассив для подписисертификатов ulHashSize 0, // ДлинаРазмер подписываемых данных массива 0); pbtSignature, // Буфер Формат подписи: 0 - неотделяемая подпись (подпись вместе с подписаннымиисходными данными ); &ulSignatureSize); // Длина подписанных данных PKCS7_DETACHED_SIGNATURE - отделяемая подпись (подпись без исходных данных) if (rv != CKR_OK) { printf(" -> Failed\n"); else break; } printf(" -> OK\n"); ... /* Распечатать буфер, содержащий подпись Освобождение памяти*/ printf("Signature buffer is: \nC_EX_FreeBuffer"); for (irv = 0pFunctionListEx->C_EX_FreeBuffer(pbtSignature); if i(rv < ulSignatureSize;!= CKR_OK) i++) {printf(" -> Failed\n"); else printf("%02X ", pbtSignature[i]); if ((i + 1) % 8 == 0) printf("\n"); } |
Подпись в формате CMS
Формат входных данных
-> OK\n"); |
Проверка подписи
Для проверки подписи данных служат функции C_SignInit()
и C_Sign()
. Сначала операцию подписи нужно инициализировать через C_SignInit()
, передав в нее идентификатор сессии, механизма и закрытого ключа. Затем размер буфера подписанных данных можно определить, вызвав C_Sign()
, и подписать данные, вызвав C_Sign()
второй раз.
При использовании совместных алгоритмов хеширования и подписи (например, CKM_GOSTR3410_WITH_GOSTR3411)
в C_Sign()
передается открытый текст для подписи, при использовании только алгоритма подписи (например, CKM_GOSTR3410
) – уже прохешированные данные.
Шифрование и расшифрование
Поддерживаемые механизмы
Устройства Рутокен поддерживают следующие механизмы шифрования:
...
Режим гаммирования с обратной связью
...
Работа с токеном
Форматирование
Смена пин-кода
Работа с сертификатами
Создание подписанного запроса на сертификат в формате PKCS#10
Получение информации о сертификате
Импорт сертификата на токен