Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Viacheslav  
#1 Оставлено : 30 августа 2021 г. 10:30:25(UTC)
Viacheslav

Статус: Новичок

Группы: Участники
Зарегистрирован: 30.08.2021(UTC)
Сообщений: 2
Российская Федерация

Сказал(а) «Спасибо»: 3 раз
Добрый день!

Прошу помочь с подписью xml запроса на КриптоПро .Net для сервиса интеграции ГИИС ДМДК https://dmdk-exch.goznak.ru/ws/v1/exchange.wsdl

Основной сайт https://dmdk.ru

Сертификат валидный, подписанный запрос проходит валидацию на https://dss.cryptopro.ru/Verify/Verify/

ТЗ от сервиса на стр 11, https://dmdk.ru/upload/i...go-servisa-v3.0.15.1.pdf
звучит так:

Цитата:
Подпись формируется по стандарту XMLDSig (https://www.w3.org/TR/xmldsig-core1/).
Тип подписи – detached signature (отделенная подпись).
Над подписываемым XML-узлом RequestData осуществляются
преобразования http://www.w3.org/2001/10/xml-exc-c14n# и urn://smevgov-ru/xmldsig/transform



Но подпись не проходит сервер в ответ пишет:

Код:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Client</faultcode>
         <faultstring xml:lang="en">Error validate signature : -2</faultstring>
         <detail>
            <ErrorDetailType xmlns:ns2="urn://xsd.dmdk.goznak.ru/exchange/1.0">
               <ns2:code>VerifySignature</ns2:code>
               <ns2:msg>Error validate signature : -2</ns2:msg>
            </ErrorDetailType>
         </detail>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>



Код:
public static void SignDmdkXml(string requestFileName, string requestSignedFileName, X509Certificate2 certificate)
            {
                // Подгружаем документ
                var xdoc = new XmlDocument();
                xdoc.Load(requestFileName);

                // Создание подписчика XML-документа
                var signedXml = new SignedXml(xdoc);

                // Установка ключа для создания подписи
                signedXml.SigningKey = certificate.PrivateKey;
                
                // Установка алгоритма нормализации узла SignedInfo (в соответствии с методическими рекомендациями СМЭВ)
                signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

                // Установка алгоритма хэширования (в соответствии с методическими рекомендациями СМЭВ)
                signedXml.SignedInfo.SignatureMethod = CPSignedXml.XmlDsigGost3410_2012_256Url;

                // Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования
                var dataReference = new Reference
                {
                    Uri = "#body",
                    DigestMethod = CPSignedXml.XmlDsigGost3411_2012_256Url
                };

                // Метод преобразования, применяемый к данным перед их подписью (в соответствии с методическими рекомендациями СМЭВ)
                //dataReference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
                var c14Trans = new XmlDsigExcC14NTransform();
                dataReference.AddTransform(c14Trans);

                var smevTrans = new XmlDsigSmevTransform();
                dataReference.AddTransform(smevTrans);

                signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform");

                // Установка ссылки на узел
                signedXml.AddReference(dataReference);

                // Установка информации о сертификате, который использовался для создания подписи
                var keyInfo = new KeyInfo();
                keyInfo.AddClause(new KeyInfoX509Data(certificate));
                signedXml.KeyInfo = keyInfo;

                // Вычисление подписи
                signedXml.ComputeSignature();

                // Получение XML-представления подписи
                var signatureXml = signedXml.GetXml();

                //// Добавление подписи в исходный документ
                xdoc.GetElementsByTagName("ds:Signature")[0].AppendChild(xdoc.ImportNode(signatureXml.GetElementsByTagName("SignedInfo")[0], true));
                xdoc.GetElementsByTagName("ds:Signature")[0].AppendChild(xdoc.ImportNode(signatureXml.GetElementsByTagName("SignatureValue")[0], true));
                xdoc.GetElementsByTagName("ds:Signature")[0].AppendChild(xdoc.ImportNode(signatureXml.GetElementsByTagName("KeyInfo")[0], true));

                var settings = new XmlWriterSettings
                {
                    Indent = false,
                    NewLineChars = Empty
                };

                using (var writer = XmlWriter.Create(requestSignedFileName, settings))
                {
                    xdoc.Save(writer);
                }
            }


Текст подписываемого запроса:

Код:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn://xsd.dmdk.goznak.ru/exchange/1.0">
<soapenv:Header/>
  <soapenv:Body>
    <ns:HealthRequest>
      <ns:CallerSignature>
        <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
      </ns:CallerSignature>
      <ns:RequestData id="body">
        <ns:DataForTest>Test</ns:DataForTest>
      </ns:RequestData>
    </ns:HealthRequest>
  </soapenv:Body>
</soapenv:Envelope>


Очень нужна помощь, сам воюю неделю пока не выходит.
Заранее спасибо!

Отредактировано пользователем 30 августа 2021 г. 19:12:09(UTC)  | Причина: Не указана

Offline two_oceans  
#2 Оставлено : 30 августа 2021 г. 14:55:10(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,342
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 90 раз
Поблагодарили: 313 раз в 295 постах
Добрый день. Подписанный запрос не вижу, так что проверить не могу. Желательно прикреплять файлом, форум искажает содержимое. Не беда если запрос без переводов строк - любой браузер его отобразит с форматированием, так что специально добавлять отступы и переводы строк не нужно.

1) По остальному напрашивается вопрос - трансформ СМЭВ точно ли нужен для этой информационной системы? В некоторых случаях системы крашатся при проверке на неопознанных трансформах;
2) Подписываете документ без удаления переводов строк, а записываете результат, удаляя переводы строк - потенциально может поломать подпись, так как каноникализация оставляет символы 0х10 без изменения (если они были). Желательно чтобы на подписание уже шел документ без лишних табуляций и переводов строк. Например, считали исходный, сразу записали во временный документ с Вашими настройками Writer, считали уже временный документ и его подписываете;
3) Пересадкой из одной подписи в другую также есть риск все поломать. Формируется не том месте или почему к этому прибегаете? В идеале вообще не пересаживать, а если пересаживаете, то весь тег Signature целиком. В частности, настораживает в коде, что берете содержимое (SignedInfo) без префиксов и вставляете в тег с префиксом ds:Signature. Если все так, то это исказит каноническую форму SignedInfo и SignatureValue будет неверно;

Не уверен насчет класса SignedXml, есть ли там такой режим, но достаточно часто используют "шаблон подписи" - формируют содержимое подписи, оставив DigestValue и SignatureValue пустыми, а метод подписания заполняет только их.
thanks 1 пользователь поблагодарил two_oceans за этот пост.
Viacheslav оставлено 30.08.2021(UTC)
Offline Viacheslav  
#3 Оставлено : 30 августа 2021 г. 15:47:33(UTC)
Viacheslav

Статус: Новичок

Группы: Участники
Зарегистрирован: 30.08.2021(UTC)
Сообщений: 2
Российская Федерация

Сказал(а) «Спасибо»: 3 раз
Автор: two_oceans Перейти к цитате
Добрый день. Подписанный запрос не вижу, так что проверить не могу. Желательно прикреплять файлом, форум искажает содержимое. Не беда если запрос без переводов строк - любой браузер его отобразит с форматированием, так что специально добавлять отступы и переводы строк не нужно.

1) По остальному напрашивается вопрос - трансформ СМЭВ точно ли нужен для этой информационной системы? В некоторых случаях системы крашатся при проверке на неопознанных трансформах;
2) Подписываете документ без удаления переводов строк, а записываете результат, удаляя переводы строк - потенциально может поломать подпись, так как каноникализация оставляет символы 0х10 без изменения (если они были). Желательно чтобы на подписание уже шел документ без лишних табуляций и переводов строк. Например, считали исходный, сразу записали во временный документ с Вашими настройками Writer, считали уже временный документ и его подписываете;
3) Пересадкой из одной подписи в другую также есть риск все поломать. Формируется не том месте или почему к этому прибегаете? В идеале вообще не пересаживать, а если пересаживаете, то весь тег Signature целиком. В частности, настораживает в коде, что берете содержимое (SignedInfo) без префиксов и вставляете в тег с префиксом ds:Signature. Если все так, то это исказит каноническую форму SignedInfo и SignatureValue будет неверно;

Не уверен насчет класса SignedXml, есть ли там такой режим, но достаточно часто используют "шаблон подписи" - формируют содержимое подписи, оставив DigestValue и SignatureValue пустыми, а метод подписания заполняет только их.


Спасибо за оперативный ответ, к сожалению не имею должного опыта работы с XMLDSIG и КриптоПро и основывался на оф. примере из SDK.

1) Согласно описанию документации требуется - поэтому принял как должное.
2) Действительно Вы правы это потенциально слабое место, которое не брал во внимание, поэтому немного расширил функционал и добавил PreserveWhitespace = saveFormat получив формат исходного запроса на лету пусть и с плоским блоком Signature.
3) Пересадку брал из примера в КриптоПро SDK в моем случае работают обе версии и корректно так как структура не сложная. Хотя сам по началу подсаживал весь Signature.

Режима "шаблон подписи" для SignedXml не нашёл на просторах интернета, но на базе класса, что ниже это можно реализовать чуть позже.

Проблема решилась благодаря Вашим наводкам вся сложность оказалась в том, что сервис требует префиксы и строго "ds" ко всем дочерним узлам Signature хотя это отступ от стандарта, который говорит о плохом тоне при использовании префиксов. Я поначалу эту версию прорабатывал так как в примерах префиксы указаны но прочитав описания стандарта подумал ну раз это гос.сервис значит все должно быть по фэншую ровно по стандарту в этот момент я и пошел не потому пути поверив чёткое следование стандарту.

К сожалению, прямого пути присвоения префиксов не нашёл воспользовался производным классом от SignedXml (https://stackoverflow.com/a/12343267) с перегрузкой методов и все получилось по крайней мере на базовым запросе дальше буду тестировать.

Спасибо!

Если кому потребуются прикладываю исходники моих черновиков:

Отредактировано пользователем 30 августа 2021 г. 19:11:42(UTC)  | Причина: Не указана

Offline two_oceans  
#4 Оставлено : 31 августа 2021 г. 13:34:50(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,342
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 90 раз
Поблагодарили: 313 раз в 295 постах
Цитата:
Пересадку брал из примера в КриптоПро SDK в моем случае работают обе версии и корректно так как структура не сложная. Хотя сам по началу подсаживал весь Signature.
Да, это значит, что выделение узла (тега, фрагмента) корректно захватывает объявления пространств имен из контекста предков (вышестоящих тегов) - в таком случае не поломается каноническая форма. Однако это все равно не очень хороший пример "как нужно делать", так как очень много незнакомых со спецификой программистов прочитают этот листинг и пытаются это же сделать в своей среде программирования на голых строковых переменных, которые конечно же не захватывают объявления пространств от вышестоящих тегов и у них все поломается.
Цитата:
Проблема решилась благодаря Вашим наводкам вся сложность оказалась в том, что сервис требует префиксы и строго "ds" ко всем дочерним узлам Signature хотя это отступ от стандарта, который говорит о плохом тоне при использовании префиксов. Я поначалу эту версию прорабатывал так как в примерах префиксы указаны но прочитав описания стандарта подумал ну раз это гос.сервис значит все должно быть по фэншую ровно по стандарту в этот момент я и пошел не потому пути поверив чёткое следование стандарту.
Рад за Вас, что у Вас получилось.

К слову скажу, первая версия моей программы также была ориентирована на префиксы - читался префикс от Signature и искались SignedInfo, SignatureValue с именно этим префиксом. Отступления от стандарта и "плохого тона" я в этом не вижу. Поясню: предположение об одинаковом префиксе на мой взгляд гораздо естественнее чем делать пересадку подписи по кусочкам, "собирая зебру из черной и белой лошадей". Про подпись стандартом оговаривается алгоритм заполнения подписи на том же месте, где она создана (хотя технически однозначность префиксов не указана, да). Про возможность "пересадки" дочерних тегов под Signature стандарт ничего не говорит, наоборот подчеркивается, что после подписания документ править нельзя. Возможность пересобирать один документ в другой добавлена трансформом исключающей канонической формы - стандарт трансформа прекрасно живет без стандарта подписания и наоборот (в частности, у них взаимоисключающие требования к переводам строк - при подписании символы с кодом 13 удаляются шагом нормализации и никогда не могут прийти на вход трансформа). Неоднозначность (по моему мнению) оставлена скорее как место для расширения формата подписи, а возможность "собрать зебру" это непредумышленный побочный эффект.

Если конкретная реализация не вставляет подпись в документ, а выдает Signature отдельно и формирует теги в неквалифицированной форме, несовместимой с задачей, то это не проблема реализации и не проблема стандарта. Проблема в выборе не того инструмента.

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

Отредактировано пользователем 31 августа 2021 г. 13:41:04(UTC)  | Причина: Не указана

thanks 1 пользователь поблагодарил two_oceans за этот пост.
Viacheslav оставлено 02.09.2021(UTC)
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.