На входе мы имеем два или более файлов (тело электронного документа и файлы отсоединённых ЭП).
Необходимо выполнить загрузку документа с ЭП в систему DIRECTUM и обеспечить удобный доступ пользователя к информации об ЭП.
И обратная задача: в системе DIRECTUM есть подписанный электронный документ, необходимо выгрузить тело документа и его ЭП в отдельные файлы.
В системе DIRECTUM «из коробки» есть возможность импортировать документы с ЭП в формате ESD (см. EDocuments.CreateNewFromFile). Посмотрим, получится ли сгенерировать ESD из имеющихся данных (файлы тела документа и ЭП). Для этого создадим в системе тестовый документ, подпишем его и экспортируем в ESD.
ESD представляет собой XML следующего содержания:
<!--?xml version="1.0" encoding="UTF-8" standalone="yes"?-->
<structuredelectronicobject metadataid="" metadataversion="" version="2.0">
<header author="Test" createdinsendersystem="true" date="" extension="DOC" globalid="{991B7778-B7D9-4AC1-A5A5-B88CD590216F}" modified="2015-12-09T17:35:55+04:00" name="Пример ESD" note="Test" number="" organization="Test" sourceedocumentid="150010485" sourceedocumentversionnumber="1" type="Document">
<extattributes>
<id isnull="false" name="ID" type="Integer" value="150010485">
<organization isnull="true" metadataid="" name="Organization" reference="Организации" type="Reference" value="">
<versionnumber isnull="false" name="VersionNumber" type="Integer" value="1">
</versionnumber></organization></id></extattributes>
<accessrights>
<links>
<contents>
<!--[CDATA[0M8R4KGxGuEAAAAAAAAAAAAAAA....]]-->
</contents>
<MetadataScheme>
<!--[CDATA[]]-->
<digitalsignatures>
<digitalsignature certificateissuedto="Test" cryptoprovider="CryptoPro Encryption" signaturetype="Approving" signed="2015-12-09T17:35:53+04:00" version="2.0">
<attributes>
<comment isnull="false" name="Comment" type="String" value="">
<signedbyusername isnull="false" name="SignedByUserName" type="String" value="Test">
<inthenameofusername isnull="false" name="InTheNameOfUserName" type="String" value="Test">
</inthenameofusername></signedbyusername></comment></attributes>
<data>
<!--[CDATA[MIIH5gYJKoZIhvcNAQcCoII...]]-->
</data>
</digitalsignature>
</digitalsignatures>
</links></accessrights></header></structuredelectronicobject>
Как видим, ESD, кроме самого тела документа и ЭП, содержит ещё много различных реквизитов (ИД, Дата изменения, криптопровайдер, имя пользователя-подписанта и т.п.).
В нашем случае, на этапе импорта мы имеем только файлы тела документа и ЭП. Некоторую информацию о сертификате и его владельце можно достать из ЭП. Но сначала проверим, можно ли без этого обойтись и импортировать в систему ESD, указав только тело документа и ЭП (в CDATA).
<!--?xml version="1.0" encoding="UTF-8" standalone="yes"?-->
<structuredelectronicobject metadataid="" metadataversion="" version="2.0"><links><links>
<header extension="" modified="" name="" type="Document">
<accessrights>
<links>
<contents>
<!--[CDATA[0M8R4KGxGuEAAAAAAAAAAAAAAA....]]-->
</contents>
<MetadataScheme>
<!--[CDATA[]]-->
<digitalsignatures>
<digitalsignature certificateissuedto="" cryptoprovider="" signaturetype="" signed="" version="">
<attributes>
<comment isnull="false" name="Comment" type="String" value="">
<signedbyusername isnull="false" name="SignedByUserName" type="String" value="">
<inthenameofusername isnull="false" name="InTheNameOfUserName" type="String" value="">
</inthenameofusername></signedbyusername></comment></attributes>
<data>
<!--[CDATA[MIIH5gYJKoZIhvcNAQcCoII...]]-->
</data>
</digitalsignature>
</digitalsignatures>
</links></accessrights></header></links></links></structuredelectronicobject>
Сначала получаем ошибку «Недопустимое имя типа подписи ""». Хорошо, означим атрибут в ESD «SignatureType="Approving"».
После этого импорт проходит, но, при просмотре ЭП документа, получаем ошибку «Подпись недостоверна».
Методом проб и ошибок можно установить минимальный набор реквизитов ESD, которые необходимо обязательно заполнить:
Бинго! Расширение документа мы знаем, тип ЭП можно выбрать «по-умолчанию», например, утверждающая (Approving), а вот с плагином оказалось не всё так просто. В системе DIRECTUM есть три плагина для взаимодействия с криптопровайдерами: Bicrypt signing, Capicom Encryption и CryptoPro Encryption. Bicrypt и CryptoPro "заточены" для одноименных CSP. Универсальным же из всех перечисленных является Capicom. На входе у нас только файлы документа и ЭП. Как и с помощью чего было выполнено подписание, мы не знаем. Из ЭП сведений об используемом криптопровайдере достать, к сожалению, не получилось.
Таким образом, в атрибуте ESD «CryptoProvider» необходимо указывать «Capicom Encryption», а «Version=”2.0”». (Подробностей описания механизмов работы с ЭП здесь касаться не буду, т.к. это тема уже отдельной статьи и даже не одной.)
Примечание: «Version=”2.0”» актуально для версии IS-Builder 7.16.0.1706 и выше. В ранних версиях IS-Builder были проблемы с плагином Capicom Encryption в части работы с ЭП, которые были сгенерированы по алгоритмам ГОСТ. Таким образом, для IS-Builder старше чем 7.16.0.1706 версию плагина указывать не нужно, но при просмотре ЭП по ГОСТ будет ошибка «Подпись недостоверна». Ещё один повод обновиться на новую версию!
У Capicom есть ещё одна особенность. Как правило, отсоединённая ЭП кодируется в BASE64 и передаётся в файле с расширением «.p7s». В ESD для плагина Capicom ЭП должна быть закодирована в BASE64 два раза (а, например, для CryptoPro хватит и одного раза). Поэтому, при формировании ESD, необходимо проверить, закодирована ли ЭП в BASE64, если нет, то закодировать 2 раза, если да, то закодировать в BASE64 ещё один раз.
После того как мы сгенерировали XML в формате ESD, можно смело импортировать структурированный документ в DIRECTUM.
При просмотре подписей в системе, пользователи смогут увидеть всю необходимую информацию: ФИО владельца сертификата и дату подписания, эти данные подтянутся автоматом, так что отдельно указывать их в ESD смысла нет.
Код можно посмотреть в функции «CreateEDocWithSigFromFile». Пакет разработки прилагается.
С экспортом ЭП в файлы всё обстоит гораздо проще. Каких-то подводных камней и хитростей здесь нет.
Выгрузить ЭП можно двумя способами.
Первый способ: через ESD (по аналогии с импортом, но в обратном порядке).
Плюсы:
Минусы:
Второй способ: получить ЭП напрямую из базы с помощью SQL-запроса. Как можно подсмотреть в справке, нас интересует таблица «SBEDocSignature», где в поле «Sign» типа «image» хранится не что иное, как Электронная подпись документа.
С помощью нехитрого SQL-запроса можно быстро достать электронные подписи документа
select
cast(cast(S.Sign as varbinary(max)) as varchar(max))
from
SBEDocSignature S (nolock)
where
S.EDocID = «ИД_Документа»
Плюсы:
Минусы: -
Пример реализации функции экспорта ЭП «ExportSignaturesFromEDocVer». Пакет разработки прилагается.
Данный функционал может применяться в интеграционных решениях, где необходима передача электронных документов с отсоединённой электронной подписью, а интегрируемая система не умеет генерировать ESD.
Пакет разработки: ImportAndExportSignedEDoc.zip
Андрей, а что думают о полученной экспортом отсоединенной ЭП внешние приложения для работы с подписями, например, Крипто АРМ?
И, кстати, о недостатках экспорта ЭП прямым запросом. Теоретически может потребоваться самостоятельно реализовывать в запросе системную логику — проверку прав доступа, например.
Проверка экспортированных ЭП выполнялась на ресурсе https://www.gosuslugi.ru/pgu/eds/. Думаю, в Крипто АРМ тоже всё будет хорошо.
А мы загружали документ и экспортированную sql-запросом ЭП в сервис Диадок - тоже нормально подхватилось.
Только есть нюанс - в веб-интерфейсе Диадок отображается, что документ подписал тот пользователь, под которым загрузили документ, а не тот, кому принадлежит сертификат. А если открыть окошечко свойств ЭП, то там уже в строке "ФИО подписанта" отображается владелец сертификата.
Мне кажется, такое поведение сервиса Диадок можно объяснить следующим образом: ЭП считается валидной и юридически значимой, если ей сопутствует доверенный штамп времени, а в отсоединенной ЭП, насколько я понимаю, этого штампа нет (или он не всегда есть). А вот в момент загрузки документа и подписи в сервис Диадок штамп времени генерируется должным образом (т.е. с помощью специального серверного ПО, удовлетворяющего требованиям и аттестованного). Поэтому сервис пишет, что подписал тот пользователь, который в данный момент взаимодействует с сервисом, т.е. под чьей учеткой загрузили документ и ЭП. И это далеко не обязательно тот же самый пользователь, которому принадлежит сертификат.
Но на некоторых документах MimeEncodeString() возвращает некорректную подпись (обрезает последние 4 символа). Причем эти документы ничем особо не отличаются (ни размером, ни форматом, ни содержанием) от всех остальных (по которым подпись конвертируется корректно).
Если эти документы выгружать в .esd формате, то там подпись верная.
Как добиться того, чтобы MimeEncodeString() работал корректно во всех случаях?
Сталкивался ли кто-то с подобным поведением этой функции?
Коллеги, выгружаю подпись методами которые описаны в данной статье, сам документ экспортирую вручную, при попытке пройти проверку на подлинность на сайте госуслуг (электронного документа. ЭП — отсоединенная, в формате PKCS#7) выдает что Электронная подпись недействительна, Подлинность документа НЕ ПОДТВЕРЖДЕНА.
При проверке на том же ресурсе ЭП, все ОК. В чем загвоздка?
Добрый день!
Подскажите, у вас ГОСТ подпись создается нормально? у меня пустой файл p7s (70 байт)
Как можно выявить проблему?
Уточнение, эта подпись не конвертируется
Андрей, большое спасибо за функцию !!!
Очень выручил !
Авторизуйтесь, чтобы написать комментарий