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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Darkf0x  
#1 Оставлено : 7 октября 2025 г. 10:14:51(UTC)
Darkf0x

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

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

Приветствую!

Пишу сервис обмена данными со СМЭВ 3.
Транспортный уровень написал без всяких проблем, благо СМЭВ сервис работает даже на тестовом стенде нормально.
но что касается подписи документа и передачи уже подписанного документа, это кромешный кошмар!!! =(((

Скачал для тестов КриптоПро .NET и признаться удручает жуткая реализация обертки, чтобы понять в чем проблема прохождения валидации, нужно просто с Бубнами
танцевать. в итоге я так проблему и не решил..
Перед вопросом приведу код, так будет проще понять тем, кто через эти шаманства проходил:

Собственно Код:
Код:

   //--------------------------------------------------------------------
   // получение сертификата из хранилища
   //--------------------------------------------------------------------
   private static CpX509Certificate2 GetCert(string certName)
   {
     error = "";
     try
     {
         using (var store = new CpX509Store(StoreName.My, StoreLocation.CurrentUser))
         {
             store.Open(OpenFlags.ReadOnly);
             var cert = store.Certificates.Find(X509FindType.FindByIssuerName, certName, false);
             if (cert != null && cert.Count > 0)
                 return cert[0];
         }
     }catch (Exception ex) { error = ex.Message; }
     return null;
   }
   //--------------------------------------------------------------------
   // Генерация раздела с подписью для конверта CМЭВ
   //--------------------------------------------------------------------
   public static XmlElement CreateSign(XmlDocument BodyForSign, string certName, string uri = "", string crtPass = "")
   {
     error = "";
     try
     {                
         CpX509Certificate2 Certificate = GetCert(certName);
         if (Certificate != null)
         {
             Gost3410_2012_256CryptoServiceProvider pKey = (Gost3410_2012_256CryptoServiceProvider)Certificate.PrivateKey;
             if (pKey != null)
             {
                 if (!string.IsNullOrEmpty(crtPass))
                     pKey.SetContainerPassword(String2SecureString(crtPass));
                 CpSignedXml signedXml = new CpSignedXml(BodyForSign);
                 if (signedXml != null)
                 {
                     signedXml.SigningKey = pKey;
                     signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform");
                     var reference = new CpReference
                     {
                         Uri = string.IsNullOrEmpty(uri) ? "" : $"#{uri}",
                         DigestMethod = CpSignedXml.XmlDsigGost3411_2012_256Url
                     };
                     signedXml.AddReference(reference);
                     signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
                     signedXml.SignedInfo.SignatureMethod = CpSignedXml.XmlDsigGost3410_2012_256Url;
                     signedXml.KeyInfo.AddClause(new CpKeyInfoX509Data(Certificate));
                     reference.AddTransform(new CpXmlDsigExcC14NTransform());
                     reference.AddTransform(new XmlDsigSmevTransform());
                     signedXml.ComputeSignature();
                     return signedXml.GetXml();
                 }
             }
             else
                 error = "[Error] - Private Key not contained in Cert";
         } 
     }            
     catch (Exception ex) 
     {
         error = ex.Message;
     }
     return null;
   }
   //--------------------------------------------------------------------
   // Верификация подписи (для проверки что подписанный документ проходит проверку)
   //--------------------------------------------------------------------
   public static bool VerifySign(XmlDocument xmlDoc)
   {
     error = "";
     try
     {
         CpSignedXml signedXml = new CpSignedXml(xmlDoc);
         if (signedXml != null)
         {
             signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform");
             XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");
             if (nodeList != null && nodeList.Count > 0)
             {
                 XmlNodeList certificates = xmlDoc.GetElementsByTagName("X509Certificate");
                 if (certificates != null && certificates.Count > 0)
                 {
                     CpX509Certificate2 certFromSignedXML = new CpX509Certificate2(Convert.FromBase64String(certificates[0].InnerText));
                     if (certFromSignedXML != null)
                     {
                         foreach (XmlElement element in nodeList)
                         {
                             signedXml.LoadXml(element);
                             bool passes = signedXml.CheckSignature(certFromSignedXML, true);
                             return passes;
                         }
                     } else { error = "[ERROR] - Get and decode base64 Certificate from signed XML"; }
                 } else { error = "[ERROR] - Get Certificate from X509Certificate tag"; }
             } else { error = "[ERROR] - Signature tag not found in signed XML"; }
         } else { error = "[ERROR] - Create Signed XML object"; }
     }
     catch (Exception ex)
     {
         error = ex.Message;
     }
     return false;
   }  
  


Дьявольщина при проверке происходит вот тут - "CpSignedXml signedXml = new CpSignedXml(xmlDoc);"
Если я передаю xmlDoc (XmlDocument) сразу же после подписи в качестве аргумента конструктора CpSignedXml,
то ВСЕ отлично!
CheckSignature возвращает - TRUE!

Но если передавать: xmlDoc.InnerXml, xmlDoc.OuterXml, причем перед подписью или после, включая-выключая параметр - PreserveWhitespace.
Передача осуществляется через промежуточные сохранения в файл и последующее чтение или создание нового объекта XmlDocument и загрузку через .LoadXml(InnerXml).
Метод CheckSignature всегда возвращает - FALSE.

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

НИЧЕГО НЕ ПОМОГАЕТ!


Самое плохое, что невозможно посмотреть что делает класс CpSignedXml с XmlDocument в своем конструкторе, берет InnerXml и что-то
делает с самим объектом XmlDocument на уровне парсинга Нод.
Что добавляет или удаляет из текста XML перед генерацией подписи?

Из-за этого СМЭВ меня отплевывает постоянно с воплями - "16006 : SMEV-100: ЭП-ОВ не соответствует подписанным данным: Нарушена целостность ЭП"

Собственно вопрос - Куда рыть-то? Явно проблемы с тем что подпись генерится по разделу InnerText, но он преобразовывается в CpSignedXml, что-то добавляется или
удаляется или приводится к какому-то формату... В итоге есть отличия в структуре текста раздела XML на основание которого создана подпись.


P.S. Уже просто неясно что в XML нужно изменить, чтобы попасть в формат который использовался при генерации ЭЦП.







Offline Артём Макаров  
#2 Оставлено : 9 октября 2025 г. 16:02:02(UTC)
Артём Макаров

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 20.02.2017(UTC)
Сообщений: 225

Сказал(а) «Спасибо»: 4 раз
Поблагодарили: 67 раз в 62 постах
Исходники CpSignedXml с поддержкой ГОСТов можно посмотреть в версии SignedXml для 3.1 на гитхабе

https://github.com/Crypt...ography/Xml/SignedXml.cs

которая содержит минимальные правки по сравнению с исходной версией от мс (ссылка на актуальные исходники из их репозитория)

https://source.dot.net/#...dXml.cs,7d7c934a64d3ebf9

В Libcore используется практически такой же код, как и в 3.1 по первой ссылке выше.


Техническую поддержку оказываем тут
Наша база знаний
Offline Darkf0x  
#3 Оставлено : 10 октября 2025 г. 16:28:12(UTC)
Darkf0x

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

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

Автор: Артём Макаров Перейти к цитате
Исходники CpSignedXml с поддержкой ГОСТов можно посмотреть в версии SignedXml для 3.1 на гитхабе

https://github.com/Crypt...ography/Xml/SignedXml.cs

которая содержит минимальные правки по сравнению с исходной версией от мс (ссылка на актуальные исходники из их репозитория)

https://source.dot.net/#...dXml.cs,7d7c934a64d3ebf9

В Libcore используется практически такой же код, как и в 3.1 по первой ссылке выше.




Чет не пашет нифига...

Написал обертку над CpSignedXml c возможностью добавления префикса "ds" к разделу "Signature"..
Одна фигня на тестовом контуре СМЭВ орет - SMEV-100: ЭП-ОВ не соответствует подписанным данным: Нарушена целостность ЭП
Хотя вроде по феншую XML собрана.. канонизированная.
Offline Артём Макаров  
#4 Оставлено : 11 октября 2025 г. 16:16:10(UTC)
Артём Макаров

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 20.02.2017(UTC)
Сообщений: 225

Сказал(а) «Спасибо»: 4 раз
Поблагодарили: 67 раз в 62 постах
Автор: Darkf0x Перейти к цитате
Автор: Артём Макаров Перейти к цитате
Исходники CpSignedXml с поддержкой ГОСТов можно посмотреть в версии SignedXml для 3.1 на гитхабе

https://github.com/Crypt...ography/Xml/SignedXml.cs

которая содержит минимальные правки по сравнению с исходной версией от мс (ссылка на актуальные исходники из их репозитория)

https://source.dot.net/#...dXml.cs,7d7c934a64d3ebf9

В Libcore используется практически такой же код, как и в 3.1 по первой ссылке выше.




Чет не пашет нифига...

Написал обертку над CpSignedXml c возможностью добавления префикса "ds" к разделу "Signature"..
Одна фигня на тестовом контуре СМЭВ орет - SMEV-100: ЭП-ОВ не соответствует подписанным данным: Нарушена целостность ЭП
Хотя вроде по феншую XML собрана.. канонизированная.


Если что, ds префиксы теперь из коробки должны работать. Попробуйте через

Код:
signedXml.SignatureNodePrefix = "ds";


перед вызовом подписи.
Техническую поддержку оказываем тут
Наша база знаний
Offline Darkf0x  
#5 Оставлено : 13 октября 2025 г. 9:21:20(UTC)
Darkf0x

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

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

Автор: Артём Макаров Перейти к цитате
Автор: Darkf0x Перейти к цитате
Автор: Артём Макаров Перейти к цитате
Исходники CpSignedXml с поддержкой ГОСТов можно посмотреть в версии SignedXml для 3.1 на гитхабе

https://github.com/Crypt...ography/Xml/SignedXml.cs

которая содержит минимальные правки по сравнению с исходной версией от мс (ссылка на актуальные исходники из их репозитория)

https://source.dot.net/#...dXml.cs,7d7c934a64d3ebf9

В Libcore используется практически такой же код, как и в 3.1 по первой ссылке выше.




Чет не пашет нифига...

Написал обертку над CpSignedXml c возможностью добавления префикса "ds" к разделу "Signature"..
Одна фигня на тестовом контуре СМЭВ орет - SMEV-100: ЭП-ОВ не соответствует подписанным данным: Нарушена целостность ЭП
Хотя вроде по феншую XML собрана.. канонизированная.


Если что, ds префиксы теперь из коробки должны работать. Попробуйте через

Код:
signedXml.SignatureNodePrefix = "ds";


действительно префикс появился, правда пришлось перед установкой префикса включить эту экпериментальную фичу через - AppContext.SetSwitch("Switch.CryptoPro.DotNet.AllowExperimental", true);
Правда это не помогло..
СМЭВ все так же ругается на ЭП.
Может я конечно не тот раздел подписываю, но я так понимаю, что крипта через установленный Uri сама находит нужный раздел в Xml документе и на базе этого раздела генерит ЭП.

Через CheckSignature все норм проверяется если передаешь до этого подписанную XML через объект XmlDocument.
Но стоит сохранить XmlDocument в XML файл, тут же прочитать его и подать в CheckSignature.. и все.. уже подпись нарушена.
Толи текст XML при сохранение в файл сохраняется не в канонизированном виде или при чтение из файла XmlDocument сериализует его в несколько другом виде.
Вообщем какая-то магия.





перед вызовом подписи.


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