Page tree

Versions Compared

Key

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

...

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

Info
title

Google Chrome/Chromium

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

...

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

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

...

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


Note

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

С помощью функции getDeviceInfo можно получить:

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

Смена PIN-кода

...

Пример смены PIN-кода на устройстве:

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

...


2. Для чтения сертификатов, хранящихся на устройстве, не требуется авторизация на устройство.

...


...

Пример чтения пользовательских сертификатов с устройства:

Code Block
languagejs
// вызывается метод 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)

...

4. Сертификат можно распарсить вызовом функции parseCertificate и получить из него DN Subject, DN Issuer, расширения, значение открытого ключа, подпись, серийный номер, срок действия и т.п.

5. Сертификат можно записать на устройство.

...

Пример записи сертификата на устройство как пользовательского:

Code Block
languagejs
 var certpem = "-----BEGIN CERTIFICATE-----
MIIBmjCCAUegAwIBAgIBATAKBgYqhQMCAgMFADBUMQswCQYDVQQGEwJSVTEPMA0G
A1UEBxMGTW9zY293MSIwIAYDVQQKFBlPT08gIkdhcmFudC1QYXJrLVRlbGVjb20i
MRAwDgYDVQQDEwdUZXN0IENBMB4XDTE0MTIyMjE2NTEyNVoXDTE1MTIyMjE2NTEy
NVowEDEOMAwGA1UEAxMFZmZmZmYwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAQYHKoUD
AgIeAQNDAARADKA/O1Zw50PzMpcNkWnW39mAJcTehAhkQ2Vg7bHkIwIdf7zPe2Px
HyAr6lH+stqdACK6sFYmkZ58cBjzL0WBwaNEMEIwJQYDVR0lBB4wHAYIKwYBBQUH
AwIGCCsGAQUFBwMEBgYpAQEBAQIwCwYDVR0PBAQDAgKkMAwGA1UdEwEB/wQCMAAw
CgYGKoUDAgIDBQADQQD5TY55KbwADGKJRK+bwCGZw24sdIyayIX5dn9hrKkNrZsW
detWY3KJFylSulykS/dfJ871IT+8dXPU5A7WqG4+
-----END CERTIFICATE-----";

// ...

// вызывается метод Promise, который должен вернуть Id устройства и Id сертификата
.then(function(rutokenHandle, certPem) {
	return plugin.importCertificate(rutokenHandle, certPem, plugin.CERT_CATEGORY_USER);
})
// Отображение подписанных данных в формате PEM
.then(function() {
	alert("Сертификат импортирован успешно");
}, handleError)

...


2. Для генерации ключевой пары требуется ввод PIN-кода. При генерации ключа можно задать параметры ключевой пары. Если опция не задана, будут выбраны параметры А для любого из алгоритмов ГОСТ.
 

...

Пример генерации ключевой пары ГОСТ Р 34.10-2012:

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

...

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

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

...

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

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

...

Code Block
-----BEGIN CMS-----
MIIDUQYJKoZIhvcNAQcCoIIDQjCCAz4CAQExDDAKBgYqhQMCAgkFADCBygYJKoZI
hvcNAQcBoIG8BIG5PCFQSU5QQURGSUxFIFVURjg+PFY+0JLRi9C/0L7Qu9C90LjR
gtGMINCw0YPRgtC10L3RgtC40YTQuNC60LDRhtC40Y4/PCE+c2VydmVyLXJhbmRv
bS1kYXRhZTI6ZGE6MmM6MDU6MGI6MzY6MjU6MzQ6YzM6NDk6Nzk6Mzk6YmI6MmY6
YzU6Mzc6ZGI6MzA6MTQ6NDQ6ODM6NjY6Njk6NmI6OWY6YTU6MDk6MzQ6YmY6YzQ6
NzY6YzmgggGeMIIBmjCCAUegAwIBAgIBATAKBgYqhQMCAgMFADBUMQswCQYDVQQG
EwJSVTEPMA0GA1UEBxMGTW9zY293MSIwIAYDVQQKFBlPT08gIkdhcmFudC1QYXJr
LVRlbGVjb20iMRAwDgYDVQQDEwdUZXN0IENBMB4XDTE0MTIyMjE2NTEyNVoXDTE1
MTIyMjE2NTEyNVowEDEOMAwGA1UEAxMFZmZmZmYwYzAcBgYqhQMCAhMwEgYHKoUD
AgIjAQYHKoUDAgIeAQNDAARADKA/O1Zw50PzMpcNkWnW39mAJcTehAhkQ2Vg7bHk
IwIdf7zPe2PxHyAr6lH+stqdACK6sFYmkZ58cBjzL0WBwaNEMEIwJQYDVR0lBB4w
HAYIKwYBBQUHAwIGCCsGAQUFBwMEBgYpAQEBAQIwCwYDVR0PBAQDAgKkMAwGA1Ud
EwEB/wQCMAAwCgYGKoUDAgIDBQADQQD5TY55KbwADGKJRK+bwCGZw24sdIyayIX5
dn9hrKkNrZsWdetWY3KJFylSulykS/dfJ871IT+8dXPU5A7WqG4+MYG7MIG4AgEB
MFkwVDELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEiMCAGA1UEChQZT09P
ICJHYXJhbnQtUGFyay1UZWxlY29tIjEQMA4GA1UEAxMHVGVzdCBDQQIBATAKBgYq
hQMCAgkFADAKBgYqhQMCAhMFAARAco5PumEfUYVcLMb1cnzETNOuWC8Goda8pdUL
W5ASK+tztCwM7wpXgAy+Y6/sLtClO9sh8dKnAaEY2Yavg3altQ==
-----END CMS-----

Проверка подписи на сервере:

Code Block
languagebash
titleПроверка подписи на сервере:
openssl cms -verify -in sign.cms -inform PEM -CAfile ca.crt -out data.file -certsout user.cr

Здесь sign.cms — файл, в котором находится подпись, ca.crt — файл с корневыми сертификатами, до одного из которых должна выстроиться цепочка, data.file — файл, в который будет сохранены подписанные данные, user.crt — файл, в который будет сохранен пользовательский сертификат. Именно из data.file нужно извлечь данные отсоединить последние 32 символа и сравнить salt.

Если на сервере нужно получить информацию из сертификата, то парсить его можно так:

...

...

  • Показать содержимое сертификата в текстовом представлении:

...


  • Code Block
    languagebash
     openssl

...

  •  x509 -in cert.pem -noout -text
  • Показать серийный номер сертификата:
    Code Block
    languagebash

...

  •  openssl x509 -in cert.pem -noout -serial

...

...

  • Показать DN субъекта (subject):

...

  • Code Block
    languagebash
    openssl x509 -in cert.pem -noout -subject

...

 

...

  • Показать DN издателя (issuer):
    Code Block
    languagebash
    openssl x509 -in cert.pem -noout -issuer

...

  • Показать почтовый адрес субъекта:
    Code Block
    languagebash

...

  • openssl x509 -in cert.pem -noout -email

 

 

  • Показать время начала действия сертификата:
    Code Block
    languagebash

...

  • openssl x509 -in cert.pem -noout -startdate

 

 

  • Показать время окончания действия сертификата:
    Code Block
    languagebash

...

...

  • openssl x509 -in cert.pem -noout -enddate

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

...

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

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

 

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

Code Block
title
languagejsШифрование данных на клиенте:
var data = "some data"

var recipientsCertsInPem = [
String.raw`-----BEGIN CERTIFICATE-----
MIICEjCCAb+gAwIBAgIJAL+E0An4CJgVMAoGCCqFAwcBAQMCMHkxCzAJBgNVBAYT
AlJVMQ8wDQYDVQQIDAZSdXNzaWExDzANBgNVBAcMBk1vc2NvdzEXMBUGA1UECgwO
WkFPIEFrdGl2LVNvZnQxEDAOBgNVBAsMB1J1dG9rZW4xHTAbBgNVBAMMFFJ1dG9r
ZW4gVEVTVCBDQSBHT1NUMB4XDTIwMTAxOTE3MjIyN1oXDTIxMTAxOTE3MjIyN1ow
MjEMMAoGA1UEAwwDbWVtMQswCQYDVQQGEwJSVTEVMBMGA1UECAwM0JzQvtGB0LrQ
stCwMGYwHwYIKoUDBwEBAQEwEwYHKoUDAgIjAQYIKoUDBwEBAgIDQwAEQIyKtSP4
WYjewCNr52fNMYDVwFPIwWgWdOi+DpJ47pBn4g6rILdZfvkAfemMs7a74is+mPyg
401mjbZPhDXCRt2jajBoMAsGA1UdDwQEAwIGwDATBgNVHSUEDDAKBggrBgEFBQcD
BDATBgNVHSAEDDAKMAgGBiqFA2RxATAvBgUqhQNkbwQmDCTQodCa0JfQmCAi0KDR
g9GC0L7QutC10L0g0K3QptCfIDIuMCIwCgYIKoUDBwEBAwIDQQCJvbdPKR9QO4zP
Xs4SK/dhzNdNzYmyCOoi7qUBYc4laKwUnhV88ENR5+VDee05w+JMIIJFuelg/QN3
W/W6SC2v
-----END CERTIFICATE-----`
]

// вызывается метод Promise, который должен вернуть Id устройства
.then(function (rutokenHandle) {
    var options = {};
	return plugin.cmsEncrypt(rutokenHandle, "", recipientsCertsInPem, data, options);
})
.then(function(msg) {
	alert(msg);
}, handleError)

Перед расшифрованием сообщение нужно обрамить PEM-заголовками "-----BEGIN PKCS7-----" и "-----END PKCS7-----":

Code Block
languagebashtitleРасшифрование данных на сервере
openssl cms -decrypt -binary -in message.cms -inform PEM -recip respondent.cer -inkey recipient.key -out drecipient.crt

...

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

...


...

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

Code Block
languagebash
openssl cms -encrypt -binary -gost28147-paramset_a-cfb -in data.file -out message.enc -outform PEM user.crt

Расшифрование данных на клиенте:

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

...