Подпись ИЭМК с помощью VipNet CSP: различия между версиями
Перейти к навигации
Перейти к поиску
Dmitriy (обсуждение | вклад) |
Dmitriy (обсуждение | вклад) |
||
(не показаны 2 промежуточные версии этого же участника) | |||
Строка 1: | Строка 1: | ||
Поиск нужного сертификата. Ищем по конкретному СНИЛСу и действующий на текущую дату. | Поиск нужного сертификата. Ищем по конкретному СНИЛСу и действующий на текущую дату. | ||
− | <pre>X509Certificate2 CertItog = find_certificate_();</pre> | + | <pre>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()); | ||
+ | </pre> | ||
<pre> public static X509Certificate2 find_certificate_() | <pre> public static X509Certificate2 find_certificate_() | ||
Строка 48: | Строка 54: | ||
return cert; | return cert; | ||
} | } | ||
+ | </pre> | ||
+ | Далее. Для подписи требуется библиотека GostCryptography (https://github.com/AlexMAS/GostCryptography). Заливаем через nuget, подключаем. | ||
+ | |||
+ | <pre> | ||
+ | using GostCryptography; | ||
+ | using GostCryptography.Cryptography; | ||
+ | using GostCryptography.Xml; | ||
+ | </pre> | ||
+ | |||
+ | Для СМЭВ пользуем доп. класс | ||
+ | Добавляем константы | ||
+ | <pre> | ||
+ | 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"; | ||
+ | </pre> | ||
+ | |||
+ | <pre> | ||
+ | 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; | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | И, собственно алгоритм подписи/ На выходе формируется отдельный файл. | ||
+ | |||
+ | <pre> | ||
+ | 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; | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | Верификация подписи | ||
+ | |||
+ | <pre> | ||
+ | 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; | ||
+ | } | ||
+ | </pre> | ||
+ | Вызов класса | ||
+ | <pre> | ||
+ | SignSmevRequestVip(args[1], args[2], CertItog); | ||
+ | VerifySmevRequestSignatureVip(args[2]); | ||
</pre> | </pre> |
Текущая версия на 23:38, 31 октября 2016
Поиск нужного сертификата. Ищем по конкретному СНИЛСу и действующий на текущую дату.
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]);