Подпись ИЭМК с помощью VipNet CSP
Поиск нужного сертификата. Ищем по конкретному СНИЛСу и действующий на текущую дату.
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]);