Search
Write a publication
Pull to refresh

Получение подписанного файла запроса к системе ФГИС ЗЕРНО (C#)

Получение подписанного файла запроса к системе ФГИС ЗЕРНО, на языке C#, с использованием CryptoPro.NET (Sharpei).

Сформировать любым "бизнес" приложением файл запроса в 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();
	}

}

Может кому поможет выйти из тупика :)

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.