
Разработка компонентов средств защиты информации
..pdf
Рисунок 1 – Импорт сертификата преподавателя
При создании сертификата используйте следующие параметры командной строки, желтым выделены параметры, которые вам нужно будет изменить:
-ic “Путь сертификата поставщика (преподавателя)”;
-ik t2 (Имя контейнера закрытого ключа поставщика (преподавателя));
-n “CN=ФИО и № группы”;
-sk “Имя контейнера с закрытым ключом”;
-pe; -ss My;
-len 1024;
“Путь к файлу создаваемого сертификата”.
Созданный сертификат будет находиться в хранилище личных сертификатов, которое можно открыть через командную строку – certmgr.msc, а также в файле по указанному вами пути.
21

Рисунок 2 – Созданный сертификат в хранилище личных сертификатов
Созданный таким образом сертификат студента будет использоваться далее для импорта на eToken.
Загрузите проект для Visual Studio под названием Lab2. В данном проекте содержится код, производящий инициализацию библиотеки PKCS#11. Добавьте заголовки функций, которые необходимо будет запрограммировать:
static void ImportCertificate(const char* fileName, const char* password);
static bool ReadCertFromFile(const char* fileName, CK_BYTE_PTR* cert, DWORD* certSize);
static void GetX509Subject(CK_BYTE_PTR cert, int certSize, CK_BYTE_PTR* subject, int* subjectSize);
static bool CreateCertFromBlob(CK_SESSION_HANDLE hSession, CK_BYTE_PTR cert, int certSize, CK_BYTE_PTR subject, int subjSize);
Здесь описаны заголовки функций, которые в дальнейшем будут использоваться для считывания и импорта сертификата. Функция
ImportCertificate(const char* fileName, const char* password) обеспечивает импорт сертификата по пути filename на eToken с ПИН-кодом password,
функция ReadCertFromFile(const char* fileName, CK_BYTE_PTR* cert, DWORD* certSize) обеспечивает чтение файла с сертификатом, функция
GetX509Subject(CK_BYTE_PTR cert, int certSize, CK_BYTE_PTR* subject, int* subjectSize) предназначена для получения темы сертификата,
функция CreateCertFromBlob(CK_SESSION_HANDLE hSession, CK_BYTE_PTR cert, int certSize, CK_BYTE_PTR subject, int subjSize)
предназначена для создания файла с сертификатом на eToken.
Добавьте в функцию main код, позволяющий считывать путь к сертификату и ПИН-код с консоли (можно использовать функцию gets(char* buffer)).
22
Объявите |
следующие |
переменные |
в |
теле |
функции |
ImportCertificate: |
|
|
|
|
|
CK_BYTE_PTR |
cert = NULL; |
|
|
|
|
DWORD |
|
|
certSize; |
|
|
CK_BYTE_PTR |
subject = NULL; |
|
|
||
int |
|
|
|
subjSize; |
Функция ReadCertFromFile(const char* fileName, CK_BYTE_PTR* cert, DWORD* certSize) считывает сертификат,
расположенный по пути fileName, массив считанных данных – cert, размер считанного сертификата – certSize. Один из способов, с помощью которого в C++ можно считать файл – создание дескриптора файла с помощью функции WinAPI CreateFileA(), получение размера файла с помощью функции GetFileSize(), чтение самого файла с помощью функции ReadFile(). Найдите дополнительную информацию о данных функциях. Запрограммируйте функцию ReadCertFromFile.
Рассмотрим функцию GetX509Subject(CK_BYTE_PTR cert, int certSize, CK_BYTE_PTR* subject, int* subjectSize). Данная функция извлекает информацию о субъекте, которому принадлежит сертификат. Т.к. сертификат x.509 имеет сложную структуру (см. теоретические сведения), задача извлечения данной информации является непростой, поэтому предлагается использовать следующий код:
static void GetX509Subject(CK_BYTE_PTR cert |
// |
|
Сертификат в двоичном представлении |
|
|
, int certSize |
|
// Размер |
сертификата |
|
|
, CK_BYTE_PTR* subject |
// Указатель на |
|
массив информации о субъекте |
|
|
, int* subjectSize |
// Размер |
|
информации о субъекте |
|
|
) { |
|
|
unsigned int i; |
|
|
unsigned char* current = cert; |
|
|
unsigned char* prev; |
|
|
unsigned char* end = cert + certSize; |
|
|
unsigned char tags[] = {0x30, 0, |
|
// |
основная последовательность |
|
|
0x30, 0, |
|
// |
последовательность, подписываемая ЭЦП |
|
|
0xa0, 1, |
|
// версия |
23
0x02, 1, |
// серийный |
номер |
|
0x30, 1, |
// подпись |
0x30, 1, |
// издатель |
0x30, 1, |
// период |
действия |
|
0x30, 1, |
// информация |
о субъекте |
|
}; |
|
*subject = NULL; |
|
*subjectSize = 0; |
|
for (i=0; i<sizeof(tags); i+=2) |
|
{ |
|
unsigned char v; unsigned int length = 0; prev = current;
if (current+2>end) return;
if (*current++ != tags[i]) return; v = *current++;
if ((v & 0x80) == 0) length = v; else
{
unsigned char lenlen = v & 0x7f;
if (current + lenlen > end) return; for (v=0; v<lenlen; v++) length =
(length<<8) + *current++;
}
if (tags[i+1]) current+=length;
}
*subject = prev;
*subjectSize = (int)(current-prev);
}
Рассмотрим функцию CreateCertFromBlob(CK_SESSION_HANDLE hSession, CK_BYTE_PTR cert, int certSize, CK_BYTE_PTR subject, int subjSize). Данная функция предназначена для записи сертификата на eToken. Обратите внимание, что одним из параметров данной функции является переменная типа CK_SESSION_HANDLE hSession. Данная переменная является дескриптором сессии работы с токеном. Для того, чтобы получить данный дескриптор, используйте функцию C_OpenSession() из списка функций pFunctionList. В
качестве параметров к данной функции передаются идентификатор
24
слота, к котрому подключен eToken, флаги CKF_SERIAL_SESSION и CKF_RW_SESSION, 2 параметра NULL, так как не используется механизм обратного вызова и уведомления, и ссылка на дескриптор &hSession. Кроме того, необходимо произвести вход под ролью пользователя на токен, с использованием функцию C_Login() из списка функций pFunctionList. В качестве параметров к данной функции передаются дескриптор сессии hSession, роль пользователя CKU_USER, ПИН-код в формате BYTE (LPBYTE)password, длина ПИН-кода strlen(password).
Рассмотрим код данной функции CreateCertFromBlob: static bool CreateCertFromBlob(CK_SESSION_HANDLE hSession
// ID сессии
, CK_BYTE_PTR cert
// сертификат
, int certSize
//размер сертификата
,CK_BYTE_PTR subject
//субъект сертификата
,int subjSize
//размер субъекта
)
{
CK_OBJECT_CLASS classAttr = CKO_CERTIFICATE; CK_CERTIFICATE_TYPE certType = CKC_X_509; unsigned long certCategory = 2;
CK_BBOOL trueVal = CK_TRUE; CK_OBJECT_HANDLE hObject;
CK_ATTRIBUTE templateArray [] =
{
{CKA_CLASS, &classAttr, sizeof(classAttr)}, {CKA_CERTIFICATE_TYPE, &certType,
sizeof(certType)},
{CKA_TOKEN, &trueVal, sizeof(trueVal)}, {CKA_SUBJECT, subject, subjSize }, {CKA_VALUE, (void *)cert, certSize }, {CKA_CERTIFICATE_CATEGORY, (void
*)&certCategory, sizeof (certCategory) }, };
int sizeOfTemplate = sizeof (templateArray) / sizeof(CK_ATTRIBUTE);
25
CK_RV rv = pFunctionList->C_CreateObject ( hSession, templateArray, sizeOfTemplate, &hObject );
if (rv) {
return false;
}
return true;
}
Здесь создается объект класса CKO_CERTIFICATE, выбирается тип сертификата CKC_X_509, категория сертификата 2, дескриптор создаваемого объекта hObject, затем создается набор атрибутов, которые присущи объекту “Сертификат x.509” на eToken, в состав которого входят указанные ранее значения, а также сам сертификат и субъект сертификата в двоичном представлении. Создается сертификат
спомощью функции C_CreateObject, которая создает объект на токене
суказанным набором атрибутов templateArray.
Также здесь используется переменная rv – она отображается результат выполнения запроса к библиотеке eToken API. Если rv = 0, значит запрос был выполнен корректно, в противном случае значение этой переменной будет соответствовать коду ошибки. Все коды ошибок находятся в файле pkcs11t.h, начинаясь с CKR.
Для получения идентификатора слота, к которому подключен eToken используйте следующую функцию:
static CK_ULONG GetFirstSlotId() {
CK_ULONG slotID = -1; |
|
|
CK_ULONG |
ulCount = 0; |
|
CK_SLOT_ID_PTR pSlotIDs |
= NULL_PTR; |
|
CK_ULONG |
i; |
|
if (pFunctionList- |
|
>C_GetSlotList(TRUE,NULL_PTR,&ulCount) == CKR_OK) { if (ulCount > 0) {
pSlotIDs = new CK_SLOT_ID[ulCount];
if ((pFunctionList- >C_GetSlotList(TRUE,pSlotIDs,&ulCount)) == CKR_OK) {
for (i=0;i < ulCount;i++){ CK_SLOT_INFO info;
if ((pFunctionList- >C_GetSlotInfo(pSlotIDs[i],&info)) == CKR_OK) {
if (info.flags & (CKF_HW_SLOT | CKF_TOKEN_PRESENT)) {
26
slotID =
pSlotIDs[i];
break;
}
}
}
}
}
}
if (pSlotIDs) {
delete[] pSlotIDs; pSlotIDs = NULL_PTR;
}
return slotID;
}
Дополните функцию ImportCertificate процедурами закрытия сессии:
pFunctionList->C_Logout( hSession ); pFunctionList->C_CloseSession( hSession );
Проверьте работоспособность программы. Загрузите с помощью нее созданный сертификат на eToken. Проверьте наличие сертификата с помощью eToken PKI Client (Значок в панели задач –> Open eToken Properties -> Advanced View).
27

Рисунок 3 – Проверка наличия сертификата на eToken
4. Задание на лабораторную работу
Необходимо создать сертификат студента, подписанный с помощью сертификата преподавателя. Требуется написать программу, которая импортирует сертификат x.509 в DER кодировке на eToken. В данной программе необходимо: произвести инициализацию библиотеки PKCS#11 для eToken, запросить путь к сертификату на жестком диске, ПИН для подключения к eToken, произвести операцию Login к eToken, считать сертификат с жестокого диска, скопировать сертификат на eToken. Проверить наличие сертификата с помощью eToken PKI Client.
5.Контрольные вопросы
1.Что такое x.509?
2.Опишите структуру сертификата x.509.
3.Опишите формат использования утилиты makecert.exe?
4.Каким образом производится подключение пользователя к eToken?
5.Как создается сертификат x.509 на eToken?
28
6. Каким образом можно проверить наличие сертификата на eToken?
29

ЛАБОРАТОРНАЯ РАБОТА №3 Разработка подсистемы обеспечения целостности
1. Цель работы
Целью работы является ознакомление с типами объектов, которые позволяет хранить и использовать eToken, приобретение навыков осуществлять операции, связанные с чтением, записью, удалением и поиском объектов на eToken.
2. Краткие теоретические сведения
Закрытый ключ RSA.
В алгоритме шифрования RSA, к отрытому ключу относят открытую экспоненту и модуль {e,n}, к закрытому ключу закрытую экспоненту и модуль {d,n} соответственно https://ru.wikipedia.org/wiki/RSA. eToken для ускорения вычислений,
использует другие компоненты – сами простые числа p и q, функцию эйлера и две дополнительные экспоненты, которые также относят к закрытому ключу. Можно рассмотреть примерную структуру PEM файла, в соответствии с которой компоненты закрытого ключа расположены. В соответствии с данной структурой, перед каждым из компонентов ключа, предварительно указывается длина компонента, затем идет сам компонент.
Рисунок 1 – Структура PEM файла
30