Подпись ИЭМК с помощью VipNet CSP: различия между версиями
Перейти к навигации
Перейти к поиску
Dmitriy (обсуждение | вклад) Нет описания правки Метка: visualeditor |
Dmitriy (обсуждение | вклад) Нет описания правки |
||
| (не показаны 3 промежуточные версии этого же участника) | |||
| Строка 1: | Строка 1: | ||
Поиск нужного сертификата. Ищем по конкретному СНИЛСу и действующий на текущую дату. | Поиск нужного сертификата. Ищем по конкретному СНИЛСу и действующий на текущую дату. | ||
< | <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_() | |||
{ | |||
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; | |||
} | |||
</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> | |||
Текущая версия от 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]);