...
Данные сценарии предполагают клиент-серверное взаимодействие, написание клиентских скриптов на JavaScript и соответствующих им серверных вызовов openssl.
Общие операции
Операции с устройством
...
Поиск подключенных устройств
...
Здесь первым параметром выступает старый PIN-код, а вторым новый PIN-код.
Работа с сертификатами
1. На токене могут храниться 3 категории сертификатов:
- пользовательские (константа в плагине CERT_CATEGORY_USER)
Это сертификаты, связанные с закрытым ключом пользователя. Применяются, например, для подписи CMS/PKCS#7, аутентификации пользователя в протоколе TLS.
Если сертификат импортируется как пользовательский, то при импорте будет произведен поиск в устройстве соответствующего ему закрытого ключа. Если такой ключ будет найден, то сертификат будет «привязан» к этому ключу. Если ключ найден не будет, то вернется ошибка. - корневые (константа в плагине CERT_CATEGORY_CA)
Это сертификаты издателей сертификатов, применяющиеся для проверки подписи под сертификатами. Подобная проверка подписи (построение цепочки доверия) позволяет определить, доверяет ли пользователь подписи другого пользователя. Например, в функции плагина verify есть режим проверки сертификата, на котором было подписано сообщение. При этом используется хранилище корневых сертификатов на токене, созданное импортом корневых сертификатов на токен. - другие (константа в плагине CERT_CATEGORY_OTHER)
Это сертификаты, которые не связаны с закрытым ключом и не являются корневыми.
2. Для чтения сертификатов, хранящихся на устройстве, не требуется авторизация на устройство.
Code Block | ||||
---|---|---|---|---|
| ||||
var certs = Array();
try
{
certs = plugin.enumerateCertificates(deviceId, plugin.CERT_CATEGORY_USER);
}
catch (error)
{
console.log(error);
} |
3. Сертификат можно экспортировать в PEM-формате:
Code Block | ||
---|---|---|
| ||
var certpem;
try
{
certpem = plugin.getCertificate(deviceId, certId);
}
catch (error)
{
console.log(error);
} |
Получится примерно такая строка:
Code Block |
---|
-----BEGIN CERTIFICATE-----
MIIBmjCCAUegAwIBAgIBATAKBgYqhQMCAgMFADBUMQswCQYDVQQGEwJSVTEPMA0G
A1UEBxMGTW9zY293MSIwIAYDVQQKFBlPT08gIkdhcmFudC1QYXJrLVRlbGVjb20i
MRAwDgYDVQQDEwdUZXN0IENBMB4XDTE0MTIyMjE2NTEyNVoXDTE1MTIyMjE2NTEy
NVowEDEOMAwGA1UEAxMFZmZmZmYwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAQYHKoUD
AgIeAQNDAARADKA/O1Zw50PzMpcNkWnW39mAJcTehAhkQ2Vg7bHkIwIdf7zPe2Px
HyAr6lH+stqdACK6sFYmkZ58cBjzL0WBwaNEMEIwJQYDVR0lBB4wHAYIKwYBBQUH
AwIGCCsGAQUFBwMEBgYpAQEBAQIwCwYDVR0PBAQDAgKkMAwGA1UdEwEB/wQCMAAw
CgYGKoUDAgIDBQADQQD5TY55KbwADGKJRK+bwCGZw24sdIyayIX5dn9hrKkNrZsW
detWY3KJFylSulykS/dfJ871IT+8dXPU5A7WqG4+
-----END CERTIFICATE----- |
4. Сертификат можно распарсить вызовом функции parseCertificate и получить из него DN Subject, DN Issuer, расширения, значение открытого ключа, подпись, серийный номер, срок действия и т.п.
5. Сертификат можно записать на устройство.
Code Block | ||||
---|---|---|---|---|
| ||||
var certpem = "-----BEGIN CERTIFICATE-----
MIIBmjCCAUegAwIBAgIBATAKBgYqhQMCAgMFADBUMQswCQYDVQQGEwJSVTEPMA0G
A1UEBxMGTW9zY293MSIwIAYDVQQKFBlPT08gIkdhcmFudC1QYXJrLVRlbGVjb20i
MRAwDgYDVQQDEwdUZXN0IENBMB4XDTE0MTIyMjE2NTEyNVoXDTE1MTIyMjE2NTEy
NVowEDEOMAwGA1UEAxMFZmZmZmYwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAQYHKoUD
AgIeAQNDAARADKA/O1Zw50PzMpcNkWnW39mAJcTehAhkQ2Vg7bHkIwIdf7zPe2Px
HyAr6lH+stqdACK6sFYmkZ58cBjzL0WBwaNEMEIwJQYDVR0lBB4wHAYIKwYBBQUH
AwIGCCsGAQUFBwMEBgYpAQEBAQIwCwYDVR0PBAQDAgKkMAwGA1UdEwEB/wQCMAAw
CgYGKoUDAgIDBQADQQD5TY55KbwADGKJRK+bwCGZw24sdIyayIX5dn9hrKkNrZsW
detWY3KJFylSulykS/dfJ871IT+8dXPU5A7WqG4+
-----END CERTIFICATE-----";
try
{
plugin.importCertificate(deviceId, certpem, plugin.CERT_CATEGORY_USER);
}
catch (error)
{
console.log(error);
} |
6. Вызовом функции deleteCertificate можно удалить сертификат с токена.
Работа с ключевыми парами ГОСТ Р 34.10-2001
1. Для получения декрипторов ключевых пар, хранящихся на устройстве, требуется ввод PIN-кода. Следует понимать, что само значение закрытого ключ получено быть не может, так как ключ является неизвлекаемым.
Code Block | ||
---|---|---|
| ||
var keys = Array();
try
{
plugin.login(deviceId, "12345678");
keys = plugin.enumerateKeys(deviceId, null);
}
catch (error)
{
console.log(error);
} |
2. Для генерации ключевой пары требуется ввод PIN-кода. При генерации ключа параметры могут быть выбраны из набора:
- A: id-GostR3410-2001-CryptoPro-A-ParamSet
- B: id-GostR3410-2001-CryptoPro-B-ParamSet
- C: id-GostR3410-2001-CryptoPro-C-ParamSet
- XA: id-GostR3410-2001-CryptoPro-XchA-ParamSet
- XB: id-GostR3410-2001-CryptoPro-XchB-ParamSet
Code Block | ||||
---|---|---|---|---|
| ||||
var options = {};
var keyId;
try
{
keyId = plugin.generateKeyPair(deviceId, "A", null, options);
}
catch (error)
{
console.log(error);
} |
3. С помощью функции deleteKeyPair ключевая пара может быть удалена с токена.
Конфигурирование openssl
Openssl поддерживает российские криптоалгоритмы, начиная с версии 1.0. Для того, чтобы их использовать, в openssl требуется подгружать engine gost. В большинстве дистрибутивов openssl эта библиотека присутствует. Чтобы engine подгружалась, можно прописать ее в конфигурационном файле openssl:
[openssl_def]
engines = engine_section
[engine_section]
gost = gost_section
[gost_section]
engine_id = gost
default_algorithms = ALL
Если конфигурационный файл openssl не расположен в стандартном месте, то путь к нему можно задать через переменную окружения OPENSSL_CONF.
Другим вариантом подгрузки engine gost является ее передача в параметрах командной строки утилиты openssl.
Если engine gost не расположена в стандартном месте, то через переменную окружения OPENSSL_ENGINES можно задать путь к директории, в которой openssl будет ее искать.
Для получения информации о том, успешен ли был вызов утилиты openssl или нет, с возможностью уточнения ошибки, требуется парсить stdout и stderror. В конце статьи приведена ссылка на PHP-скрипт, который использует данную утилиту.
Теперь перейдем к реализации законченных пользовательских сценариев.
Регистрация на портале
Сертификат выдается при регистрации в системе
- Получаем список подключенных к компьютеру устройств Рутокен ЭЦП
- Генерируем ключевую пару ГОСТ Р 34.10-2001 на выбранном Рутокен ЭЦП
- Cоздаем запрос PKCS#10 на сертификат для сгенерированной ключевой пары
- Отправляем запрос на сервер
- На сервере создаем сертификат, привязываем к аккаунту (сам сертификат или его дескриптор). Следует отметить, что дескрипторы сертификатов, полученные при вызове функции enumerateCertificates, являются уникальными и неизменными
- Отправляем сертификат на клиент
- На клиенте визуализируем полученный сертификат
- Импортируем полученный сертификат в Рутокен ЭЦП
Последовательность вызовов в клиентском скрипте будет следующей: