Сформировать любым "бизнес" приложением файл запроса в xml, например, для получения списка партий ЗЕРНА:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn://x-artefacts-mcx-gov-ru/fgiz-zerno/api/ws/types/1.0.3">
<soapenv:Header/>
<soapenv:Body>
<ns:SendRequestRequest>
<ns:MessageData Id="SIGNED_BY_CALLER">
<ns:MessageID>a45468ed-c26c-4a5b-995d-b12b6364fb18</ns:MessageID>
<ns:ReferenceMessageID>a45468ed-c26c-4a5b-995d-b12b6364fb18</ns:ReferenceMessageID>
<ns:MessagePrimaryContent>
<ns:RequestGetListLot status="SUBSCRIBED" xmlns:ns="urn://x-artefacts-mcx-gov-ru/fgiz-zerno/api/ws/lots/1.0.3" xmlns:ns1="urn://x-artefacts-mcx-gov-ru/fgiz-zerno/api/organizations/1.0.3">
<ns:Paging pageNumber="0" pageLength="100"/>
</ns:RequestGetListLot>
</ns:MessagePrimaryContent>
</ns:MessageData>
<ns:InformationSystemSignature>
</ns:InformationSystemSignature>
</ns:SendRequestRequest>
</soapenv:Body>
</soapenv:Envelope>
Файл может быть в любом "человекочитаемом виде", содержащим переносы, отступы и т.д.
В файле обязательно должен быть тег "<ns:MessageData Id="SIGNED_BY_CALLER">"
По нему мы определяем подписываемый блок.
В файле обязательно должен быть пустой блок, куда мы при помощи функции вставим подпись и всё, что требуется к ней
<ns:InformationSystemSignature>
</ns:InformationSystemSignature>
Это изначально файл запроса с тегом "SendRequestRequest".
Для получения сразу файла запроса результата (после того, как система приняла запрос), без дополнительных манипуляций, у функции есть параметр "isResponse".
Если его установить в true, то мы получим подписанный текст файла запроса результата, типа "SendResponseRequest" (просто заменим теги до подписи в изначальном файле).
Код получения подписанного файла.
Используется CryptoPro.NET
using CryptoPro.Sharpei.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Xml;
static string getSignXmlFile(string textXmlFile, AsymmetricAlgorithm Key, X509Certificate Certificate, bool isResponse = false)
{
if(isResponse) textXmlFile = textXmlFile.Replace("SendRequestRequest", "SendResponseRequest"); // Замена типа запроса
XmlDocument doc = new XmlDocument(); // Создаем новый XML документ.
doc.PreserveWhitespace = true; // Пробельные символы участвуют в вычислении подписи и должны быть сохранены для совместимости с другими реализациями.
//doc.Load(new XmlTextReader(FileName)); // Читаем документ из файла.
doc.LoadXml(textXmlFile); // Читаем документ из строки
if (isResponse)
{
XmlNode MessagePrimaryContent = doc.SelectSingleNode("//*[local-name()='MessagePrimaryContent']");
doc.SelectSingleNode("//*[local-name()='MessageData']").RemoveChild(MessagePrimaryContent);
}
SignedXml signedXml = new SignedXml(doc); // Создаем объект SignedXml по XML документу.
signedXml.SigningKey = Key; // Добавляем ключ в SignedXml документ.
Reference reference = new Reference();
reference.Uri = "#SIGNED_BY_CALLER"; // Создаем ссылку на node для подписи.
// Проставляем алгоритм хэширования
reference.DigestMethod = CPSignedXml.XmlDsigGost3411_2012_256Url; // CryptoPro.Sharpei.Xml
// Добавляем transform для канонизации.
var c14 = new XmlDsigExcC14NTransform();
reference.AddTransform(c14);
// Добавляем СМЭВ трансформ.
// начиная с .NET 4.5.1 для проверки подписи, необходимо добавить этот трансформ в довернные:
// signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform");
var smev = new XmlDsigSmevTransform(); // CryptoPro.Sharpei.Xml
reference.AddTransform(smev);
signedXml.AddReference(reference); // Добавляем ссылку на подписываемые данные
KeyInfo keyInfo = new KeyInfo(); // Создаем объект KeyInfo.
keyInfo.AddClause(new KeyInfoX509Data(Certificate)); // Добавляем сертификат в KeyInfo
signedXml.KeyInfo = keyInfo; // Добавляем KeyInfo в SignedXml.
// Алгоритм подписи берётся автоматически (из ключа)
//signedXml.SignedInfo.SignatureMethod = CPSignedXml.XmlDsigGost3411_2012_256HMACUrl;
signedXml.SignedInfo.CanonicalizationMethod = c14.Algorithm;
signedXml.ComputeSignature(); // Вычисляем подпись.
XmlElement xmlDigitalSignature = signedXml.GetXml(); // Получаем XML представление подписи и сохраняем его в отдельном node.
doc.SelectSingleNode("//*[local-name()='InformationSystemSignature']").AppendChild(doc.ImportNode(xmlDigitalSignature, true));
// При наличии стартовой XML декларации ее удаляем
// (во избежание повторного сохранения)
if (doc.FirstChild is XmlDeclaration)
{
doc.RemoveChild(doc.FirstChild);
}
/*
// Сохраняем подписанный документ в файле.
using (XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false)))
{
xmltw.WriteStartDocument();
doc.WriteTo(xmltw);
}
*/
// Сохраняем подписанный документ в строке и возвращаем
using (var stringWriter = new StringWriter())
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
doc.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
return stringWriter.GetStringBuilder().ToString();
}
}