Page tree

Versions Compared

Key

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

В данной статье будет расписана описана типичная схема подобной интеграции, основанная на следующих сценариях использования плагинаПлагина:

  • Регистрация на портале (с выдачей сертификата или по имеющемуся сертификату)
  • Строгая аутентификация на портале
  • Электронная подпись данных и/или файлов в формате CMS
  • Шифрование данных и/или файлов в формате CMS

Table of Contents

Данные сценарии предполагают клиент-серверное взаимодействие, написание клиентских скриптов на JavaScript и соответствующих им серверных вызовов opensslOpenSSL.

Общие операции

Так как все функции Плагина выполняются в отдельных

Info
titleGoogle Chrome/Chromium

Если вы открываете локальную страницу, убедитесь, что в настройках расширения Адаптер Рутокен Плагин включена опция "Разрешить открывать локальные файлы по ссылкам"

Общие операции

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

Code Block
languagejs
titleДобавление Promise обработчика
promise.then(onFulfilled, onRejected)
// onFulfilled – функция, которая будет вызвана с результатом при успешном выполнении асинхронной функции.
// onRejected – функция, которая будет вызвана с ошибкой при ошибке выполнения асинхроннной функции.

Операции с устройством

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

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

...

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

Получение информации об устройстве

Для определения типа устройства следует использовать функцию getRutokenModelName() репозитория https://github.com/AktivCo/blade-runner.github.iorutoken-model-by-hw-features-js

Параметр функции getDeviceInfo TOKEN_INFO_DEVICE_TYPE – устарел и не поддерживается.

...

  • модель устройства
  • метку устройства
  • серийный номер устройства
  • информацию о том, залогинен ли пользователь на устройство

Смена PIN-кода

Code Block
languagejs
titleПример смены PIN-кода на устройстве:
// вызывается метод Promise, который должен вернуть Id устройства
.then(function(rutokenHandle){
	options={}
	return plugin.changePin(rutokenHandle, "12345678", "12345678", options)
})
.then(function() {
	alert("PIN изменен успешно");
}, handleError)


Здесь первым параметром выступает старый PIN-код, а вторым новый PIN-код. 

 

Работа с сертификатами

1. На токене могут храниться 3 категории сертификатов:

...

Code Block
languagejs
titleПример чтения пользовательских сертификатов с устройства:
// вызывается метод Promise, который должен вернуть Id устройства
.then(function(rutokenHandle) {
	return plugin.enumerateCertificates(rutokenHandle, plugin.CERT_CATEGORY_USER);
})
// ПодписаниеВывод данныхпервого изнайденного текстового полясертификата на первом найденном сертификатеРутокене
.then(function(certs) {
	if (certs.length > 0) {
		// ...
	} else {
		return Promise.reject("Сертификат на Рутокен не обнаружен");
	}
}, handleError)

...

6. Вызовом функции deleteCertificate можно удалить сертификат с токена.

Работа с ключевыми парами ГОСТ


1. Для получения дескрипторов ключевых пар, хранящихся на устройстве, требуется ввод PIN-кода. Следует понимать, что само значение закрытого ключ получено быть не может, так как ключ является неизвлекаемым.

...

Code Block
languagejs
titleПример генерации ключевой пары ГОСТ Р 34.10-2012:
// вызывается метод Promise, который должен вернуть Id устройства
.then(function(rutokenHandle) {
	return plugin.generateKeyPair(rutokenHandle, undefined, marker, options);
})
.then(function(keyId) {
	alert("Ключевая пара сгенерирована успешно");
}, handleError)

3. С помощью функции deleteKeyPair ключевая пара может быть удалена с токена.

("Ключевая пара сгенерирована успешно");
}, handleError)

3. С помощью функции deleteKeyPair ключевая пара может быть удалена с токена.

Создание и проверка электронной подписи

1. Для создание подписи используется метод sign:

Code Block
languagejs
titleПодпись данных
// Подпись
.then(function(certHandle, textToSign) {
var options = {};
return plugin.sign(rutokenHandle, certHandle, textToSign, plugin.DATA_FORMAT_PLAIN, options);
)

Последние аргумент – опции функции. Их подробный список можно найти в документации, некоторые из них:

  • detached:bool (false) - генерировать отсоединенную подпись
  • addUserCertificate:bool (true) - включить в подпись сертификат пользователя
  • addSignTime:bool (false) - включить в подпись время подписи
  • useHardwareHash:bool (false) - производить аппаратное хеширование данных на ключах ГОСТ
  • rsaHashAlgorithm:enum - алгоритм хеширования при использовании ключей RSA, варианты: HASH_TYPE_MD5, HASH_TYPE_SHA1, HASH_TYPE_SHA256, HASH_TYPE_SHA512. Нужно обязательно указывать при подписи на RSA ключах.


Предпоследний аргумент определяет формат подписываемых данных:

  • DATA_FORMAT_PLAIN. Используется для подписи незакодированных данных.
  • DATA_FORMAT_BASE64 Используется для подписи данных в base64 формате.
  • DATA_FORMAT_HASH. Используется для подписи готового хеша. Для корректной работы необходимо выставить опцию detached в true.


2.  Для проверки подписи используется метод verify:

Code Block
languagejs
titleПодпись данных
// Проверка подписи
.then(function(certPem, CA, cms) {
var options = {certificates: [certPem], CA: CA};
return plugin.verify(rutokenHandle, cms, options);
})

Последние аргумент – опции функции. Их подробный список можно найти в документации, некоторые из них:

  • data:string (null) - подписанные данные (текстовые или base64-encoded), только в случае detached подписи;
  • base64:bool (false) - указывает, закодированы ли данные, переданные в data, в base64;
  • certificates:string[] (null) - набор сертификатов в PEM формате, на которых необходимо проверять подпись, при этом сертификаты, которые содержатся в cms, будут проигнорированы;
  • CA:string[] (null) - список дополнительных корневых сертификатов в PEM формате для проверки сертификата, кроме них берутся сертификаты с устройства;
  • CRL:string[] (null) - список отозванных сертификатов в PEM формате;
  • useHardwareHash:bool (false) - производить хеширование на устройстве (игнорируется для алгоритмов отличных от ГОСТ Р 34.10-2001);
  • verifyCertificate:bool (true) - проверить сертификат пользователя;

Конфигурирование openssl


См. инструкцию Интеграция ГОСТ 2012 с Рутокен ЭЦП и OpenSSL 1.1.0 или новее, раздел Установка и настройка OpenSSL для работы с rtengine 0.7.x


Теперь перейдем к реализации законченных пользовательских сценариев.

Регистрация на портале

Сертификат выдается при регистрации в системе

  • Получаем список подключенных к компьютеру устройств Рутокен ЭЦП 2.0
  • Генерируем ключевую пару по ГОСТ Р 34.10-2012 на выбранном Рутокен ЭЦП 2.0
  • Cоздаем запрос PKCS#10 на сертификат для сгенерированной ключевой пары
  • Отправляем запрос на сервер
  • На сервере создаем сертификат, привязываем к аккаунту (сам сертификат или его дескриптор). Следует отметить, что дескрипторы сертификатов, полученные при вызове функции enumerateCertificates, являются уникальными и неизменными
  • Отправляем сертификат на клиент
  • На клиенте визуализируем полученный сертификат
  • Импортируем полученный сертификат в Рутокен ЭЦП 2.0

...

Дальнейшая последовательность вызовов на клиенте:

 

 

Сертификат уже имеется на токене, выдан внешним УЦ

Ключевая пара при этом должна быть создана в формате, совместимом с библиотекой rtPKCS11ECP для Рутокен ЭЦП 2.0.

...

Code Block
languagebash
titleПоказать время окончания действия сертификата:
openssl x509 -in cert.pem -noout -enddate

Строгая аутентификация на портале

Общая схема аутентификации, используемая в Рутокен Плагин, выглядит следующим образом: 

...


Реализация данной схемы ничем принципиально не отличается от «Регистрация, сертификат уже имеется, выдан внешним УЦ».

Электронная подпись данных и/или файлов в формате CMS

  • формируется текстовое сообщение (строка), формирование сообщения может происходить как на сервере, так и на клиенте
  • если требуется подписать документ произвольного формата (например, PDF), то требуется перекодировать его в формат base64
  • строка, содержащая данные для подписи, передается в функцию sign
  • если строка представляет собой закодированные в base64 данные, то параметр функции isBase64 должен быть установлен в true, при этом перед подписью произойдет декодирование данных из base64
  • если требуется использовать аппаратное вычисление хэш-функции ГОСТ Р 34.11-94 (сертифицированная реализация, скорость 60-70 Кб/c), то в options нужно установить опцию useHardwareHash в true. Если данная опция установлена в false, то будет использована быстрая программная реализация хэш-функции ГОСТ Р 34.11-2012
  • если требуется сформировать “отсоединенную” (detached) подпись CMS, то нужно установить опцию detached в true, иначе будет сформирована “присоединенная” (attached) подпись
  • для того, чтобы включить/не включить пользовательский сертификат в подписанное CMS-сообщение существует опция addUserCertificate
  • Установка опции addSignTime в true приведет к тому, что в подписанное CMS-сообщение будет добавлено системное время в качестве подписанного атрибута

Проверка подписи на сервере описана выше.

Шифрование/расшифрование данных и/или файлов в формате CMS

Шифрование данных на клиенте для сервера

Для того, чтобы обеспечить конфиденциальность обмена данными между клиентом и сервером в плагине предусмотрено шифрование/расшифрование данных. Данные шифруются в формате CMS. Для того, чтобы зашифровать данные в формате CMS, требуется сертификат открытого ключа «адресата». При этом расшифровать такое сообщение сможет только владелец закрытого ключа. При шифровании данных для сервера рекомендуется хранить сертификат сервера на Рутокен ЭЦП 2.0. Этот сертификат может быть записан на устройство при регистрации пользователя на портале. Для этого следует использовать функцию importCertificate, при этом в качестве параметра category следует передать CERT_CATEGORY_OTHER. Для использования в функции cmsEncrypt нужно получить тело сертификата по его дескриптору с помощью функции getCertificate. При этом дескриптор является уникальным и неизменным и может быть сохранен в учетной записи пользователя на сервере при импорте сертификата сервера. Для того, чтобы использовалось аппаратное шифрование по ГОСТ 28147-89, требуется установить опцию useHardwareEncryption в true. В противном случае будет использована быстрая программная реализация ГОСТ 28147-89. 

Последовательность вызовов приведена на картинке:

...

recipient.crt — сертификат того, для кого зашифровано сообщение, recipient.key — ключ того, для кого зашифровано сообщение.

Расшифрование данных, полученных с сервера, на клиенте

Для расшифрования данных, полученных с сервера, предназначена функция cmsDecrypt. Так как сервер шифрует для клиента, используя его сертификат, то в качестве keyId должен быть передан дескриптор закрытого ключа клиента, соответствующий открытому ключу в сертификате. Этот дескриптор является уникальным и неизменным и потому может быть сохранен в учетной записи пользователя на сервере. Кроме того, дескриптор ключа пользователя может быть получен явным образом, путем вызова функции getKeyByCertificate.

...

Code Block
languagejs
titleРасшифрование данных на клиенте:
// вызывается метод Promise. Переменные rutokenHandle и keyHandle должны быть во внешном блоке.
.then(function () {
    var options = {};
    return plugin.cmsDecrypt(rutokenHandle, keyHandle, cms, options);
})
.then(function(msg) {
    alert(msg);
}, handleError)

Полезные ссылки


Данные ссылки могут быть полезны разработчикам инфосистем с поддержкой ЭП на базе Рутокен Плагин и opensslOpenSSL:

Пример интеграции Рутокен Плагин в ДБО
WEBВеб-сервис генерации ключей, формирования запросов, управления сертификатами, формирования шаблонов запросов на сертификаты 
Документация по использованию утилиты openssl OpenSSL с российскими крипталгоритмамикриптоалгоритмами