ИНТЕРФЕЙС COM

Проверка подписи XMLDSIG (WS-Security) с помощью сервиса СПЭП СМЭВ
Проверка подписи XMLDSIG на примере СМЭВ

Для взаимодействия со СМЭВ, все исходящие сообщения информационной системы, подключенной к СМЭВ, должны быть подписаны с целью удостоверения данных. Требования к алгоритмам создания электронной подписи информационной системы следующие:

Сообщение СМЭВ представляет собой XML документ, который подписывается ЭП по формату XMLDSIG (спецификация WS-Security). Подробное описание алгоритма создания ЭП находится в методических рекомендациях СМЭВ. Алгоритм можно реализовать самостоятельно, но в данной статье создание ЭП будем выполнять с помощью программных продуктов компании КриптоПро.

Первым делом выполняем установку продуктов КриптоПро CSP и КриптоПро CADESCOM. К сожалению они являются платными, но использовать триальную версию можно 90 дней. Если подпись будет создаваться на клиенте (&НаКлиенте), то устанавливаем на клиентскую машину КриптоПро. Если же создание подписи будет происходит на сервере (&НаСервере), то соответственно устанавливаем КриптоПро на тот компьютер, где установлен сервер 1С:Предприятие.

После установки продуктов КриптоПро, устанавливаем сертификат электронной подписи с привязкой к закрытому ключу в хранилище сертификатов на тот компьютер, где будет выполняться создание ЭП (см. рисунок 1). Хранилище сертификатов делится два типа: хранилище пользователя и локального компьютера. Если создание подписи будет выполнять сервер, то рекомендуется установить сертификат в хранилище локального компьютера, так как в этом случае всем пользователям системы будет доступен сертификат. Если же вы точно знаете от имени какого пользователя будет происходит создание подписи, то можно установить сертификат в хранилище пользователя (например, USR1CV82).

Создание подписи на платформе 1С выполняется с помощью COM-объектов, которые регистрируются в процессе установки КриптоПро CADESCOM. Сам XML документ перед созданием подписи подготавливается соответствующим образом. В заголовок XML документа вставляется структура Security по спецификации WS-Security с сертификатом ЭП, в формате Base64. Описание создания структуры Security в заголовке находится в статье Подготовка SOAP-сообщения перед созданием подписи XMLDSIG на примере СМЭВ, сертификат в формате Base64 помещается в структуру в момент создания подписи.
ИC органа власти (потребителя) при формировании запроса к ИС поставщика, а также ИС поставщика при формировании ответа должны проставлять в атрибуте actor значение, соответствующее СМЭВ как стороне проверяющей подпись:

Алгоритм

1. Находим установленный сертификат в хранилище сертификатов. Поиск осуществляется с помощью COM-объекта CAPICOM. Store по отпечатку, можно и по другим свойствам искать сертификат, но для однозначной идентификации лучше по отпечатку.

Так же поиск сертификатов можно выполнять и объектом МенеджерКриптографии платформы 1С.

МенеджерКриптографии = Новый МенеджерКриптографии(“Crypto-Pro GOST R 34.10-2001 Cryptographic Service Provider”, “”, 75);
ХранилищеСертификатов = МенеджерКриптографии. ПолучитьХранилищеСертификатов(
    ТипХранилищаСертификатовКриптографии. ПерсональныеСертификаты,
    РасположениеХранилищаСертификатовКриптографии. ДанныеПользователяОС);
Сертификат = ХранилищеСертификатов. НайтиПоОтпечатку(Base64Значение(ОтпечатокBase64));

В рамках поставленной задачи поиск сертификата объектом МенеджерКриптографии не подходит.

2. Создаем COM-объект CAdESCOM. CPSigner, для которого указываем найденный сертификат и секретный ключ. Секретный ключ – это пароль, установленный на контейнер закрытого ключа, запрашивается при каждом обращении к нему.

CPSigner = Новый COMОбъект(“CAdESCOM. CPSigner”);
CPSigner. Certificate = Сертификат;
CPSigner. KeyPin = СекретныйКлюч;

3. Вставляем в подготовленный XML документ найденный сертификат в формате Base64 и передаем его в свойство Content COM-объекта CAdESCOM. SignedXML с указанием типа подписи в свойстве SignatureType – в данном случае по шаблону XML документа. Создаем подпись, вызвав метод Sign(), параметром которого будет COM-объект CAdESCOM. CPSigner.

СтрокаXML = СтрЗаменить(СтрокаXML, “#Certificate_ENCODE_BASE64”, Сертификат. Export(CADESCOM_ENCODE_BASE64));
SignedXML = Новый COMОбъект(“CAdESCOM. SignedXML”);
SignedXML. Content = СтрокаXML;
SignedXML. SignatureType = CADESCOM_XML_SIGNATURE_TYPE_TEMPLATE;
ПодписаннаяXMLСтрока = SignedXML. Sign(CPSigner)

Итоговый программный код

Материал статьи основан на примере создания и проверки подписи документа XML по шаблону, который размещен в руководстве разработчика КриптоПро.

Создание электронной подписи может завершиться ошибкой неприятной ошибкой
“Неправильный параметр набора ключей”, один из вариантов решения такой ошибки приведен в статье Неправильный параметр набора ключей при создании ЭП на стороне сервера.

2.

DJ_Codebase

Сейчас в теме

на сервере был установлен КриптоПро 5 вер, компонента КриптоПро ЭЦП

может быть вызов происходит на клиенте?

Попробуй на сервере создать COMОбъект

5.

Maznud

Сейчас в теме

Здравствуйте решили как то проблему?

6.

diar01

Сейчас в теме

да, установили еще компоненту

КриптоПро CADESCOM (версия 2.0.14071)

7.

Maznud

Сейчас в теме

Спасибо большое! ошибки нет, но куда двигаться дальше? где конкретно “CMS SignedData в DER-кодировке”?

8.

vsyaschenko

Сейчас в теме

Приветсвую! Не поделитесь кодом, где Вы получаете ЭП в формате CMS SignedData в DER-кодировке?

9.

diar01

Сейчас в теме

У меня так

10.

vsyaschenko

Сейчас в теме

Спасибо! Правда интересно получается, я устанавливаю аналогичным образом значения свойств объектов и передаю те же значения аргументов в те же методы. Получаю невалидную подпись.

3.

sivin-alexey

Сейчас в теме

Обращаемся в личный кабинет системы “Честный знак”, ГИС МТ (ИС МП) за информацией о маркировке, товарах, документах и т.д. используя предоставляемый API. Отправляем собственный исходящий документ. Разбираемся с электронной подписью на клиенте и на сервере.

Этот материал является доработкой публикации: //infostart.ru/public/1276725/

Обращение к API ГИС МП ничем бы не отличалось от обращения к любым другим API, если бы не необходимость использовать электронную подпись. В этом и заключается основная сложность реализации собственного клиента.

Процедура ПолучиьТокен(Команда)

Соединение = Новый HTTPСоединение(Сервер, 443,,,,, Новый ЗащищенноеСоединениеOpenSSL);

// 1. Запрос авторизацией: возвращает УИД и текст, который надо подписать.
Запрос = Новый HTTPЗапрос(БазовыйАдресСтенда + “/auth/cert/key”);
Ответ = Соединение. ВызватьHTTPМетод(“GET”, Запрос);
ОтветЗапросаАвторизации = Ответ. ПолучитьТелоКакСтроку(“UTF-8”);
ОтветЗапросаАвторизации = СтруктураИзJSON(ОтветЗапросаАвторизации);

// 2. Текст, полученный из запроса вторизации, надо зашифровать и подписать.
ТекстДляПодписывания = ОтветЗапросаАвторизации.data;
ТекстДляПодписывания = ЗашифроватьBase64(ТекстДляПодписывания, КодировкаТекста. UTF8);
ПодписанныйТекст = ПодписатьТекст(ТекстДляПодписывания, Отпечаток, Ложь);

// Структура данных для запроса токена.
Данные = Новый Структура;
Данные. Вставить(“uuid”, ОтветЗапросаАвторизации.uuid);
Данные. Вставить(“data”, ПодписанныйТекст);

ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON. УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Данные); // превращаем в JSON
Данные = ЗаписьJSON. Закрыть();

Заголовки = Новый Соответствие; // заголовки для запроса токена
Заголовки. Вставить(“Content-Type”, “application/json; charset=UTF-8”);
Заголовки. Вставить(“Accept”, “application/json”);

// 3. Запрос получения аутентификационного токена: возвращает данные с токеном.
Запрос = Новый HTTPЗапрос(БазовыйАдресСтенда + “/auth/cert/”, Заголовки);
Запрос. УстановитьТелоИзСтроки(Данные,
КодировкаТекста. UTF8,
ИспользованиеByteOrderMark. НеИспользовать);
Ответ = Соединение. ОтправитьДляОбработки(Запрос);
Ответ = СтруктураИзJSON(Ответ. ПолучитьТелоКакСтроку());

Токен = Ответ.token;

КонецПроцедуры

Для получения токена нужно выполнить два запроса. Первым запросом мы получаем два параметра для второго запроса. На промежуточном шаге, один из этих параметров следует зашифровать и подписать электронной подписью.

Реализация функций ПодписатьТекст() и ПолучитьСертификатПоОтпечатку() почти полностью взята из руководства:

После получения токена можно выполнять запросы уже без использования электронной подписи, как обычно:

А теперь остановимся на отправке документов. Сложность состоит в том, что одного только токена для отправки таких запросов уже недостаточно. Отправляемые документы нужно правильно подписать электронной подписью.

Рассмотрим на примере отправки документа “Отгрузка” в формате XML. Любые другие документы будут отправляться точно также, только со своими параметрами. Сформированный и готовый к отправке документ выглядит так:

Метод для отправки любых документов описан в в пункте 3.1 описания API. Это метод POST и для него надо сформировать тело запроса следующим образом:

ТелоЗапроса = Новый Структура;
ТелоЗапроса. Вставить(“document_format”, “XML”);
ТелоЗапроса. Вставить(“product_document”, ТекстДокументаBase64);
ТелоЗапроса. Вставить(“type”, “LP_SHIP_GOODS_XML”);
ТелоЗапроса. Вставить(“signature”, ПодписанныйТекст);

Параметр type это и есть тип документа “Отгрузка”. Полное описание всех типов находится в справочнике “Типы документов”. Параметр product_document это текст XML, зашифрованный функцией ЗашифроватьBase64(), которая описана выше. А параметр signature это результат, возвращенный функцией ПодписатьТекст(), которая также описана выше, только для документов третий параметр этой функции нужно указывать равным ИСТИНА.

Работа на стороне сервера

Добавлю пару слов о работе на стороне сервера. В приложенных обработках вы найдёте всю выше описанную реализацию на стороне клиента. Для полноценной автоматизации нужна логика, работающая в процессе сервера. Для этого нужно где-то в настройках указать используемый сертификат (так как выбрать его интерактивно на форме нет возможности). Для этого хорошо подходит справочник “Сертификаты ключей электронной подписи и шифрования” из БСП. Он есть во всех современных типовых конфигурациях.

При использовании справочника сертификатов из БСП есть один важный момент. Отпечаток сертификата в этом справочнике хранится не в том виде, в котором он нужен для функции ПодписатьТекст(). Перед вызовом ПодписатьТекст() нужно получить отпечаток в виде HEX-строки следующим образом:

ДанныеСертификата = Сертификат. ДанныеСертификата. Получить();
ск = Новый СертификатКриптографии(ДанныеСертификата);
Отпечаток = ПолучитьHexСтрокуИзДвоичныхДанных(ск. Отпечаток);

В этом коде “Сертификат” это ссылка на элемент справочника “Сертификаты ключей электронной подписи и шифрования”.

Приложение

Я прилагаю две обработки. Первая была опубликована ещё до того, как я разобрался с документами. Вторая обработка уже включает отправку документа. Старался писать максимально кратко и понятно. Смотрите, пользуйтесь. Вопросы в комментариях приветствуются!

Всё тестировалось на платформе 8.3.18 в конфигурации Бухгалтерия предприятия 3.0.82.24.

В данной статье рассмотрим использование электронно-цифровой подписи на сайте.

Что необходимо, чтобы человек смог использовать электронно-цифровую подпись на сайте?

1) Попытка создать объект cades.
Нужно сделать примечание, что тут и далее, будет деление на браузер с ActiveX(читай IE) и остальные.
Проверка будет осуществляться:

return (‘ActiveXObject’ in window);

Если проверка прошла неудачно, то уведомляем об этом пользователя.
Стоит иметь ввиду, что после обновления хрома до версии 42 (спасибо статье за информацию) нужно включить:

Следующая проверка — а разрешен ли плагин для запуска (не для IE проверка)?

Проверяем на СКЗИ путем попытки открыть хранилище.

Проверяем на существование сертификатов в хранилище:

И их количество (бывает, что Certificates есть, но пуст, что нам тоже не подойдет):

Первый шаг сделали — проверили возможность подписания чего-либо.

Выбор электронной цифровой подписи

У клиента может быть установлено несколько сертификатов. Сертификаты могут быть от разных удостоверяющих центров (УЦ), выданными быть разным людям, с разными датами выдачами, поэтому надо предоставить выбор, каким именно он хочется воспользоваться.

1) Группируем по удостоверяющим центрам
Информация об удостоверяющем центре хранится в сертификате.

certs. Item(i). GetInfo

где certs — сертификаты из хранилища, см выше
i — порядковый номер сертификата от 1 (обратите внимание) до certs. Count.
Обратите внимание, что, в случае «кривых» сертификатов, вернуться может и undefined, имеет смысл сделать один дефолтный УЦ для таких случаев.

Теперь мы знаем список УЦ, услугами которых воспользовался клиент.
Запоминаем их и выведем через optgroup.
Сам text у option будет таким:

cert. GetInfo

+ ‘ (‘ + formatDate(cert. ValidFromDate) + ‘ – ‘ + formatDate(cert. ValidToDate) + ‘)’

в cert. GetInfo

— кому выдан сертификат
в ValidFromDate — с какого срока сертификат начал/начнет действие
в ValidToDate — соответственно, до какого срока

Ну и форматирование даты стандартное:

Еще можно подсветить option.
Зеленым — для работоспособных сертификатов, красным — нет.
Информацию можно получить при помощи самого сертификата.

Стоит отметить, что сама по себе данная проверка имеет малую ценность, ибо все причины не может отсечь.
Но самые базовые, например, проверка даты — проверяет.

В value у option запишем отпечаток cert. Thumbprint.
Можно порядковый номер записать, можно другие данные — на ваше усмотрение.

Подписание
Ну и, собственно, самый главный шаг, к которому мы стремились — подписание.

1) Находим выбранный сертификат.
Для нашего примера:

0 — означает, что мы ищем по отпечатку
1 — что используем первый результат выборки (по факту единственный)

где cert — сертификат, при помощи которого подписываем
text — собственно, что подписываем
Ну а в return возвращается подписанное сообщение.

p.s. По максимуму код постарался вычистить от специфики проекта. Если кому-то этот материал пригодится и будет интересно — напишу и серверную часть. Проверка подписанного сообщения (с цепочкой и без), проверка сертификата (ocsp и без), использования tsp и т.д.

Программы для ЭЦП

Для работы с Электронной подписью нужно установить необходимые программы. Перечислим их:

Программы и утилиты для Криптографии

Важно: Стандартный пароль на носитель: 1234567890 .

Корневые сертификаты Головного Удостоверяющего Центра


ИНТЕРФЕЙС COM

КриптоПро ЭЦП Browser plug-in

КриптоПро ЭЦП Browser plug-in предназначен для создания и проверки электронной подписи (ЭП) на веб-страницах и поддерживает работу с широким набором алгоритмов, как встроенных в операционную систему, так и доустановленных дополнительно.

Вниманию пользователей браузеров на основе Chromium Для стабильной работы браузерного расширения рекомендуется обновить браузер до последней версии (104+). Причина описана на форуме.

Для работы плагина выполните следующие шаги

1 Установите криптопровайдер

Для создания и проверки электронных подписей по алгоритмам ГОСТ требуется обязательная установка криптопровайдера, поддерживающего ГОСТ (мы рекомендуем КриптоПро CSP).

2 Установите КриптоПро ЭЦП Browser plug-in

Приложение осуществляет взаимодействие веб-страниц в вашем браузере с криптопровайдером в операционной системе и предназначено для создания и проверки электронной подписи на веб-страницах. Рекомендуем воспользоваться инструкцией по установке

3 Проверьте работу установленного плагина

Чтобы убедиться, что всё установлено верно и все элементы системы надёжно взаимодействуют, мы создали специальную площадку для тестирования и проверки создания электронной подписи.

Описание принципов работы плагина

КриптоПро ЭЦП Browser plug-in легко встраивается и применим в любом из современных браузеров с поддержкой сценариев JavaScript:

Поддерживаемые операционные системы:

КриптоПро ЭЦП Browser plug-in позволяет подписывать различные типы данных:

С точки зрения бизнес-функций, плагин позволяет использовать ЭП:

Например: В онлайн-банке подтверждение операции по переводу средств усовершенствованной электронной цифровой подписью обеспечит гарантию того, что счетом распорядился владелец в конкретный (подтвержденный) момент времени и сертификат ключа подписи на момент совершения транзакции был действителен.

КриптоПро ЭЦП Browser plug-in позволяет создавать и проверять как обычную электронную подпись, так и усовершенствованную электронную подпись. Поскольку плагин является частью стандарта применения усовершенствованной электронной цифровой подписи, автоматически решаются задачи:

Создание и проверка подписи происходят на стороне пользователя. При создании подписи с помощью КриптоПро ЭЦП Browser plug-in, электронная подпись может быть либо добавлена к подписываемым данным (присоединенная ЭП), либо создана отдельно (отделенная ЭП).

КриптоПро ЭЦП Browser plug-in распространяется бесплатно (лицензионное соглашение).

На нашем сайте доступна демо-страница для пробной работы с КриптоПро ЭЦП Browser plug-in. Полная инструкция по установке доступна по ссылке.

Время на прочтение


ИНТЕРФЕЙС COM

Важное вступление

Для получения штампа времени использован TSP-сервис http://qs.cryptopro.ru/tsp/tsp.srf

Что имеем на входе?

Лицензирование ПО и версииКриптоПро CSP версии 5.0 – у меня установлена версия 5.0.11944 КС1, лицензия встроена в ЭП. КриптоПро TSP Client 2.0 и КриптоПро OCSP Client 2.0 – лицензии покупается отдельно, а для гайда мне хватило демонстрационного срока. КриптоПро . NET Client версии 1.0.7132.2 – в рамках этого гайда я использовал демонстрационную версию клиентской части и все действия выполнялись локально. Лицензию на сервер нужно покупать отдельно. Контур. Крипто бесплатен, но требует регистрации. В нем также можно подписать документы КЭП, УКЭП и проверить созданную подпись загрузив ее файлы.

Так, а что надо на выходе?

А на выходе надо получить готовое решение, которое сделает отсоединенную ЭП в формате .sig со штампом времени на подпись и доказательством подлинности. Для этого зададим следующие критерии:

Соберем проект с поддержкой ГОСТ Р 34. 11-2012 256 bit

Гайд разделен на несколько этапов. Основная инструкция по сборке опубликована вместе с репозиторием DotnetCoreSampleProject – периодически я буду на нее ссылаться.

Первым делом создадим новую папку

Инструкция делится на 2 этапа – мне пришлось выполнить оба, чтобы решение заработало. В папку добавьте подпапки .
untime и .packages

I – Сборка проекта без сборки corefx для Windows

На этом месте у вас должно получиться решение, которое поддерживает ГОСТ Р 34.11-2012 256 bit.

Немного покодим

Потребуется 2 COM библиотеки: “CAPICOM v2.1 Type Library” и “Crypto-Pro CAdES 1.0 Type Library”. Они содержат необходимые объекты для создания УКЭП.

В этом примере будет подписываться BASE64 строка, содержащая в себе PDF-файл. Немного доработав код можно будет подписать hash-значение этого фала.

Основной код для подписания был взят со страниц Подпись PDF с помощью УЭЦП- Page 2 (cryptopro.ru) и Подпись НЕОПРЕДЕЛЕНА при создании УЭЦП для PDF на c# (cryptopro.ru), но он использовался для штампа подписи на PDF документ. Код из этого гайда переделан под сохранение файла подписи в отдельный файл.

Условно процесс можно поделить на 4 этапа:

Пробный запуск

Для подписания возьмем PDF-документ, который содержит надпись “Тестовое заявление.”:

Больше для теста нам ничего не надо

Далее запустим программу и дождемся подписания файла:


ИНТЕРФЕЙС COM

Готово. Теперь можно приступать к проверкам.

Проверка в КриптоАРМ

Время создания ЭП заполнено:

Штамп времени на подпись есть:


ИНТЕРФЕЙС COM

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


ИНТЕРФЕЙС COM

В протоколе проверки есть блоки “Доказательства подлинности”, “Штамп времени на подпись” и “Время подписания”:


ИНТЕРФЕЙС COM

ИНТЕРФЕЙС COM

ИНТЕРФЕЙС COM

Важно отметить, что серийный номер параметров сертификата принадлежит TSP-сервису http://qs.cryptopro.ru/tsp/tsp.srf

Проверка на Госуслугах


ИНТЕРФЕЙС COM

Проверка в Контур. Крипто


ИНТЕРФЕЙС COM

Done.

Гайд написан с исследовательской целью – проверить возможность подписания документов УКЭП с помощью самописного сервиса на . NET Core 3.1 с формированием штампов подлинности и времени подписания документов.

Безусловно это решение не стоит брать в работу “как есть” и нужны некоторые доработки, но в целом оно работает и подписывает документы подписью УКЭП.

Это вообще законно?

С удовольствием узнаю ваше мнение в комментариях.

UPD1: Поменял в коде переменную, куда записываются байты файла подписи.

Также я забыл написать немного про подпись штампа времени – он подписывается сертификатом владельца TSP-сервиса. По гайду это ООО “КРИПТО-ПРО”:


ИНТЕРФЕЙС COM

UPD2: Про библиотеки CAdESCOM и CAPICOM

Если создать пустой проект на . NET Core 3.1, подключив непропатченные библиотеки, то при обращении к закрытому ключу выпадет исключение “System. NotSupportedException” c сообщением “The certificate key algorithm is not supported.”:


ИНТЕРФЕЙС COM

. NET Core 3.1 – Исключение без пропатченных библиотек

Но при использовании пропатченных библиотек это исключение не выпадает и с приватным ключем можно взаимодействовать:


ИНТЕРФЕЙС COM

Также код из гайда работает с . NET Framework 4.8 без использования пропатченных библиотек, но вместо обращения к пространству имен “System. Security. Cryptography”, которое подменяется пропатченными библиотеками для . NET Core, CSP Gost3410_2012_256CryptoServiceProvider будет использован из пространства имен “CryptoPro. Sharpei”:


ИНТЕРФЕЙС COM

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *