Подпись ИЭМК с помощью VipNet CSP
Версия от 23:38, 31 октября 2016; Dmitriy (обсуждение | вклад)
Поиск нужного сертификата. Ищем по конкретному СНИЛСу и действующий на текущую дату.
X509Certificate2 CertItog = find_certificate_(); Console.WriteLine(CertItog.SignatureAlgorithm.Value); Console.WriteLine(CertItog.GetPrivateKeyInfo().KeyContainerName); Console.WriteLine(CertItog.GetPrivateKeyInfo().ProviderName); Console.WriteLine(CertItog.GetPrivateKeyInfo().ProviderType); Console.WriteLine(CertItog.GetPrivateKeyInfo());
public static X509Certificate2 find_certificate_() { X509Store store = new X509Store("MY", StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); X509Certificate2 cert = new X509Certificate2(); X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates; X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false); string str_SN = ""; foreach (X509Certificate2 x509 in fcollection) { try { if (x509.Subject.ToUpper().Contains("SNILS") || x509.Subject.ToUpper().Contains("СНИЛС")) { str_SN = x509.Subject.Substring(x509.Subject.IndexOf("SNILS") + 6, 11); int n; if (!int.TryParse(str_SN.Substring(0, 10), out n)) { str_SN = x509.Subject.Substring(x509.Subject.ToUpper().IndexOf("СНИЛС") + 6, 11); if (!int.TryParse(str_SN.Substring(0, 10), out n)) { continue; // System.Windows.Forms.MessageBox.Show("Снилс в сертификате не найден или пустой"); } } if (String.CompareOrdinal(str_SN, "NNNNNNNNNNNNN") == 0) { cert = x509; // Console.WriteLine(cert.Subject); Console.WriteLine(str_SN); // Console.ReadKey(); break; } } x509.Reset(); } catch (CryptographicException) { Console.WriteLine("Information could not be written out for this certificate."); } } store.Close(); return cert; }
Далее. Для подписи требуется библиотека GostCryptography (https://github.com/AlexMAS/GostCryptography). Заливаем через nuget, подключаем.
using GostCryptography; using GostCryptography.Cryptography; using GostCryptography.Xml;
Для СМЭВ пользуем доп. класс Добавляем константы
private const string WsSecurityExtNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; private const string WsSecurityUtilityNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
private static XmlElement GetSmevIdElement(XmlDocument document, string idValue) { var namespaceManager = new XmlNamespaceManager(document.NameTable); namespaceManager.AddNamespace("wsu", WsSecurityUtilityNamespace); return document.SelectSingleNode("//*[@wsu:Id='" + idValue + "']", namespaceManager) as XmlElement; }
И, собственно алгоритм подписи/ На выходе формируется отдельный файл.
private static XmlDocument SignSmevRequestVip(string FileName, string SignedFileName, X509Certificate2 signingCertificate) { XmlDocument smevRequest = new XmlDocument(); smevRequest.PreserveWhitespace = true; smevRequest.Load(new XmlTextReader(FileName)); // Создание подписчика XML-документа var signedXml = new GostSignedXml(smevRequest) { GetIdElementHandler = GetSmevIdElement }; // Установка ключа для создания подписи signedXml.SetSigningCertificate(signingCertificate); // signedXml.SigningKey = signingCertificate.PrivateKey; // var SigningKey = signingCertificate.GetPrivateKeyAlgorithm(); signedXml.SigningKey = signingCertificate.GetPrivateKeyAlgorithm(); // var gostFormatter = new GostSignatureFormatter(signingCertificate.GetPrivateKeyAlgorithm()); // Console.WriteLine(signatureXml1.InnerText); Console.ReadKey(); // Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования ГОСТ Р 34.11-94 (в соответствии с методическими рекомендациями СМЭВ) var dataReference = new Reference { Uri = "#BODY", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl }; // Метод преобразования, применяемый к данным перед их подписью (в соответствии с методическими рекомендациями СМЭВ) var dataTransform = new XmlDsigExcC14NTransform(); dataReference.AddTransform(dataTransform); // Установка ссылки на узел signedXml.AddReference(dataReference); //reference #wsa300 var dataReferenceWSA300 = new Reference { Uri = "#WSA-300", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl }; var dataTransformWSA300 = new XmlDsigExcC14NTransform(); dataReferenceWSA300.AddTransform(dataTransformWSA300); signedXml.AddReference(dataReferenceWSA300); //reference #WSA-301 var dataReferenceWSA301 = new Reference { Uri = "#WSA-301", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl }; var dataTransformWSA301 = new XmlDsigExcC14NTransform(); dataReferenceWSA301.AddTransform(dataTransformWSA301); signedXml.AddReference(dataReferenceWSA301); //reference #WSA-302 var dataReferenceWSA302 = new Reference { Uri = "#WSA-302", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl }; var dataTransformWSA302 = new XmlDsigExcC14NTransform(); dataReferenceWSA302.AddTransform(dataTransformWSA302); signedXml.AddReference(dataReferenceWSA302); //reference #WSA-303 var dataReferenceWSA303 = new Reference { Uri = "#WSA-303", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl }; var dataTransformWSA303 = new XmlDsigExcC14NTransform(); dataReferenceWSA303.AddTransform(dataTransformWSA303); signedXml.AddReference(dataReferenceWSA303); //reference #TRHEAD var dataReferenceTRHEAD = new Reference { Uri = "#TRHEAD", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl }; var dataTransformTRHEAD = new XmlDsigExcC14NTransform(); dataReferenceTRHEAD.AddTransform(dataTransformTRHEAD); signedXml.AddReference(dataReferenceTRHEAD); // smevRequest.GetElementsByTagName("wsse:BinarySecurityToken")[0].InnerText = Convert.ToBase64String(signingCertificate.RawData); //reference #CertId var dataReferenceCertId = new Reference { Uri = "#CertId", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl }; var dataTransformCertId = new XmlDsigExcC14NTransform(); dataReferenceCertId.AddTransform(dataTransformCertId); signedXml.AddReference(dataReferenceCertId); var keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(signingCertificate)); signedXml.KeyInfo = keyInfo; // Установка алгоритма нормализации узла SignedInfo (в соответствии с методическими рекомендациями СМЭВ) signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; // Установка алгоритма подписи ГОСТ Р 34.10-2001 (в соответствии с методическими рекомендациями СМЭВ) signedXml.SignedInfo.SignatureMethod = GostSignedXml.XmlDsigGost3410ObsoleteUrl; // Вычисление подписи signedXml.ComputeSignature(); // Получение XML-представления подписи var signatureXml = signedXml.GetXml(); // Console.WriteLine(signatureXml.GetElementsByTagName("SignatureValue")[0].InnerText); Console.ReadKey(); // Добавление подписи в исходный документ smevRequest.GetElementsByTagName("Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignatureValue")[0], true)); smevRequest.GetElementsByTagName("Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignedInfo")[0], true)); using (XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false))) { smevRequest.WriteTo(xmltw); } return smevRequest; }
Верификация подписи
private static bool VerifySmevRequestSignatureVip(string FileName) { XmlDocument signedSmevRequest = new XmlDocument(); signedSmevRequest.PreserveWhitespace = true; signedSmevRequest.Load(new XmlTextReader(FileName)); // Создание подписчика XML-документа var signedXml = new GostSignedXml(signedSmevRequest) { GetIdElementHandler = GetSmevIdElement }; // Поиск узла с подписью var nodeList = signedSmevRequest.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl); // Загрузка найденной подписи signedXml.LoadXml((XmlElement)nodeList[0]); // Поиск ссылки на BinarySecurityToken var references = signedXml.KeyInfo.GetXml().GetElementsByTagName("Reference", WsSecurityExtNamespace); if (references.Count > 0) { // Определение ссылки на сертификат (ссылка на узел документа) var binaryTokenReference = ((XmlElement)references[0]).GetAttribute("URI"); if (!String.IsNullOrEmpty(binaryTokenReference) && binaryTokenReference[0] == '#') { // Поиск элемента с закодированным в Base64 сертификатом var binaryTokenElement = signedXml.GetIdElement(signedSmevRequest, binaryTokenReference.Substring(1)); if (binaryTokenElement != null) { // Загрузка сертификата, который был использован для подписи var signingCertificate = new X509Certificate2(Convert.FromBase64String(binaryTokenElement.InnerText)); // Проверка подписи bool result = signedXml.CheckSignature(signingCertificate.GetPublicKeyAlgorithm()); if (result) { Console.WriteLine("Подпись №{0} верна."); } else { Console.WriteLine("Подпись №{0} не верна."); } return result; } } } return false; }
Вызов класса
SignSmevRequestVip(args[1], args[2], CertItog); VerifySmevRequestSignatureVip(args[2]);