Как подписывать с помощью ЭЦП электронные документы различных форматов | ITSec.Ru

Как подписывать с помощью ЭЦП электронные документы различных форматов | ITSec.Ru ЭЦП

Анализ исходных данных

Загружаем с портала СМЭВ 3:

Если уже умеем формировать обычный XMLDSig или подписывать, например, конверты сообщений СМЭВ 2, то больше всего начинает интересовать, чем же отличается конверт с подписью СМЭВ 3 от СМЭВ 2.

Открываем пример конверта СМЭВ 3 SendRequestRequestNoAttach.xml

Вариант 3. воспользоваться веб-сервисами

Можно подписать документ любого формата, не устанавливая на компьютер специальных программ, — например, в веб-сервисе Контур.Крипто.

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

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

Для документов формата pdf

Для создания и проверки электронной подписи в программах Adobe Acrobat, Adobe Reader и Adobe LiveCycle ES есть отдельный модуль КриптоПро PDF.

КриптоПро PDF прилагается бесплатно при совместном использовании с программой Adobe Reader. В остальных программах также есть тестовый период, по истечении которого нужно приобрести лицензию.

Прежде чем вставить электронную подпись в документе PDF, необходимо установить и настроить Acrobat Reader DC или Adobe Acrobat Pro для работы с программой КриптоПро PDF.

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

Подготовка к подписи по правилам смэв 3

Apache Santuario изначально ничего не знает про ГОСТ криптографические алгоритмы и СКЗИ КриптоПро.

В библиотеке xmlsec-1.5.0.jar в файле orgapachexmlsecurityresourceconfig.xml содержатся настройки только для работы с зарубежными криптографическими алгоритмами.

Чтобы он начал распознавать и применять ГОСТ, нужно выполнить его инициализацию.

По старинке это делалось так:

//APACHE-SANTUARIO INIT WITH CryptoPro JCP
        System.setProperty("org.apache.xml.security.resource.config", "resource/jcp.xml");
        org.apache.xml.security.Init.init();
        String cfile1 = System.getProperty("org.apache.xml.security.resource.config");
        LOGGER.log(Level.INFO, "Init class URL: "   org.apache.xml.security.Init.class.getProtectionDomain().getCodeSource().getLocation());
        LOGGER.log(Level.INFO, cfile1);

В новых версиях КриптоПро JCP (JCSP) инициализацию выполнит одна строчка:

ru.CryptoPro.JCPxml.xmldsig.JCPXMLDSigInit.init();


Теперь нужно Apache Santuario научить новым правилам трансформации, которые диктует СМЭВ 3. Для этого регистрируем класс трансформации:

  try {
                Transform.register(SmevTransformSpi.ALGORITHM_URN, SmevTransformSpi.class.getName());
                santuarioIgnoreLineBreaks(true);
                LOGGER.log(Level.INFO, "SmevTransformSpi has been initialized");
            } catch (AlgorithmAlreadyRegisteredException e) {
                LOGGER.log(Level.INFO, "SmevTransformSpi Algorithm already registered: "   e.getMessage());
            } 

Заодно сразу выполняем требование из Методических указаний:

Требования к форматированию В XML-структуре подписи между элементами не допускается наличие текстовых узлов, в том числе переводов строки.

santuarioIgnoreLineBreaks(true);

    private static final String IGNORE_LINE_BREAKS_FIELD = "ignoreLineBreaks";

/**
     * Apache Santuario privileged switch IgnoreLineBreaks property
     * 
     * @param mode
     */
    private void santuarioIgnoreLineBreaks(Boolean mode) {
        try {
            Boolean currMode = mode;
            AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
                
                public Boolean run() throws Exception {
                    Field f = XMLUtils.class.getDeclaredField(IGNORE_LINE_BREAKS_FIELD);
                    f.setAccessible(true);
                    f.set(null, currMode);
                    return false;
                }
            });
            
        } catch (Exception e) {
            LOGGER.warning("santuarioIgnoreLineBreaks "   ExceptionUtils.getFullStackTrace(e));
        }
    }

Делается это в привилегированном блоке AccessController.doPrivileged

и через reflection, из-за особенности реализации свойства ignoreLineBreaks в Santuario.

Просто через настройку системного свойства:

System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");

не работает.

Через настройку опции JVM:

-Dcom.sun.org.apache.xml.internal.security.ignoreLineBreaks=true

работает.

Если взглянуть на код класса org.apache.xml.security.utils.XMLUtils, то можно увидеть, что поле ignoreLineBreaks статическое, инициализируется в привилегированном блоке из системного свойства «org.apache.xml.security.ignoreLineBreaks».

private static boolean ignoreLineBreaks =
        AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
            public Boolean run() {
                return Boolean.valueOf(Boolean.getBoolean
                    ("org.apache.xml.security.ignoreLineBreaks"));
            }
        }).booleanValue();
public static boolean ignoreLineBreaks() {
        return ignoreLineBreaks;
    }

Такая реализация приводит к невозможности гибко настроить в одном Java процессе для части методов игнорировать перевод строк, а для другой части не игнорировать.

Т.е., если одно приложение выполняет подписи XMLDsig, СМЭВ 2 и СМЭВ 3, все XML документы, обработанные Santuario должны на выходе лишиться перевода строк.

С этим свойством, конечно, возникает вопрос к Apache Santuario:

Подписать документ с помощью криптопро 5.0 — уц айтиком

В КриптоПРО версии 5.0 добавлена возможность подписывать документы электронной подписью с помощью утилиты Инструменты КриптоПро. Данная утилита входит в состав пакета установки КриптоПро 5.0, устанавливать отдельно ее не нужно.

Скачать КриптоПро 5.0 можно по ссылке.

Для подписания документа:

1. Откройте меню «Пуск», в списке программ найдите папку КРИПТО-ПРО, откройте её. Запустите приложение Инструменты КриптоПро.

Ярлык Инструменты КриптоПро

2. Перейдите во вкладку «Создание подписи», нажмите на кнопку «Выбрать файл для подписи».

Создание подписи Инструменты КриптоПро

3. В открывшемся окне выберите файл, который необходимо подписать. Нажмите кнопку «Открыть».

Выбор файла Инструменты КриптоПро

4. Под кнопками «Выбрать файл для подписи» и «Сохранить подпись как» отобразится путь исходного файла и путь подписанного файла, который в дальнейшем будет создан.

Обратите внимание! По умолчанию КриптоПро 5.0 подписывает файлы в формате .p7s. Если требуется подписать файл в другом формате (к примеру, .sig), необходимо в конце пути будущего подписанного файла заменить .p7s на .sig.
Поддерживаемые форматы:
.p7s
.sig
.sgn
Формат подписи Инструменты КриптоПро

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

5. Выберите, какой электронной подписью необходимо подписать документ.

Выбор сертификата Инструменты КриптоПро

6. Нажмите кнопку «Подписать«. После завершения процесса подписания Вы увидите сообщение «Создание подписи завершилось успехом«, а так же в указанной директории будет создан файл с указанным расширением (.p7s / .sig / .sgn) – это и есть подписанный файл.

Подписать документ Инструменты КриптоПро
Подписанный документ КЭП
Обратите внимание! По умолчанию КриптоПро 5.0 создает присоединённую подпись.
Если Вам необходимо создать отсоединённую подпись, перед подписанием (шаг 6) нажмите кнопку «Показать расширенные» и поставьте галочку «Создать отсоединённую подпись».
Расширенные настройки Инструменты КриптоПро

Подписанный документ вы можете проверить с помощью нашей инструкции

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

Вам необходимо предоставить подписанное квалифицированной ЭП заявление и подписанную доверенность (в случаях выпуска на сотрудника).

Для прикрепления данных документов, необходимо перейти в заявку на выпуск подписи и выбрать «Анкета и документы».

Внимание! Документы не принимаются в случае:
— Если они находятся в архиве.
— Если они имеют расширение отличающееся от .sig, .p7s, .sgn
.
— Документ должен быть подписан прикрепленной подписью, открепленные подписи не принимаются.

В открывшемся окне необходимо выбрать раздел «Документы».

Как подписывать с помощью ЭЦП электронные документы различных форматов | ITSec.Ru

Далее необходимо загрузить документы в правильные поля.

Подписанное заявление загружается в поле:

Как подписывать с помощью ЭЦП электронные документы различных форматов | ITSec.Ru

Необходимо нажать на данное поле, откроется окно выбора необходимого документа, выберите подписанное заявление и нажмите «ОК», либо перетяните документ прямо на данную иконку.

Подписанная доверенность загружается в поле:

Как подписывать с помощью ЭЦП электронные документы различных форматов | ITSec.Ru

Необходимо нажать на данное поле, откроется окно выбора необходимого документа, выберите подписанное заявление и нажмите «ОК», либо перетяните документ прямо на данную иконку.

Подпись в html-форме

Такая задача возникает при встраивании средств ЭЦП в системах с «тонким» клиентом, когда пользователь работает в системе через Web-браузер (MS IE). В таких системах поступают следующим образом: создается скрытое hidden-поле в форме. Когда пользователь нажимает кнопку типа «подписать и отправить», соответствующий скрипт обработчика (например, на VBScript) формирует строковую переменную, в которую методом конкатенации записывают важную информацию по идентификации документа и содержимое текстовых полей, которые ввел пользователь.

Далее сформированная строковая переменная подписывается. Чаще всего используются методы объектов CAPICOM.dll, неотделенная подпись. Подписанная строковая переменная и есть электронный документ. Подписанный документ (подписанная строка) записывается в hidden-поле и методом POST передается на сервер.

Серверное приложение проверяет подпись в переменной, полученной из hidden-поля, и в зависимости от результатов проверки ЭЦП и содержательной части электронного документа осуществляет его дальнейшую обработку. Важным моментом является сохранение подписанного документа на сервере.

Подпись в базе данных

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

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

Подпись документов в формате xml

Если документ представлен в формате XML, то имеется несколько подходов к формированию его подписей: формирование ЭЦП ХМL-документов XMLdsig для Windows (MSXML5, MSXML6) с использованием Microsoft Office InfoPath 2003 — новой составляющей системы Microsoft Office;

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

Подпись многофайловых документов

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

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

Подпись сообщений смэв 3

Для подписи документов СМЭВ 3 все готово.

Код подписания выглядит следующим образом:

Проблемы. хэш не совпадает

Внимание!

Для отладки использовался пример конверта СМЭВ 3 SendRequestRequestNoAttach.xmlИз него был удален элемент ds:Signature с целью подписать сообщение заново и сверить с оригиналом.

Несмотря на то, что метод подписи и трансформация SmevTransformSpi, взятая из Методических указаний, отрабатывали, на выходе был подписанный документ, подпись которого при онлайн-проверке на портале СМЭВ 3 трактовалась как

ЭП-ОВ не подтверждена: Ошибка проверки ЭП: Нарушена целостность ЭП


Почему

не совпадал с оригинальным примером:

Для диагностики причин в класс SmevTransformSpi в метод process был добавлен свой XMLEventWriter.

ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLEventWriter bdst =
outputFactory.get().createXMLEventWriter(baos, ENCODING_UTF_8); 

для параллельного анализа всех этапов трансформации.

Нормализованный элемент XML, на который требуется поставить подпись, выглядел следующим образом:

Поиск решения показал, что, во-первых

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

Во-вторых, привел в GitHub, где был выложен класс SmevTransformSpi более старой версии.

Старая версия класса трансформации выдала следующий нормализованный документ:

С ним хэш стал совпадать, а подпись успешно проходить валидацию.

Сравнение версий класса SmevTransformSpi показала, что помимо добавленных в новой реализации дополнительных функций логирования и диагностики в debug режиме:

if (logger.isDebugEnabled()) {
                debugStream = new DebugOutputStream(argDst);
                dst = outputFactory.get().createXMLEventWriter(debugStream, ENCODING_UTF_8);
            } else {
                dst = outputFactory.get().createXMLEventWriter(argDst, ENCODING_UTF_8);
            }


Класс из Методических указаний не содержит нужную строчку, или содержит опечатку:

Отсутствует строка:

prefixMappingStack.pop();

, которая удаляет первый объект из стека с префиксами

  Stack<List<Namespace>> prefixMappingStack = new Stack<List<Namespace>>();

, что приводило к неверной работе SmevTransformSpi.

Добавление этой строки в новую версию SmevTransformSpi.java решило проблему.

Проверка подписи сообщения смэв 3

Код проверки подписи выглядит следующим образом:

Результаты

Подписание конвертов СМЭВ 3 выполняется успешно.

Сообщения проходят проверку на портале Электронного правительства Госуслуги

И в собственном приложении:

Оцените статью
ЭЦП64
Добавить комментарий