forked from AlexMAS/GostCryptography
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SignedXmlSmevTest.cs
132 lines (103 loc) · 6.21 KB
/
SignedXmlSmevTest.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Xml;
using GostCryptography.Cryptography;
using GostCryptography.Tests.Properties;
using GostCryptography.Xml;
using NUnit.Framework;
namespace GostCryptography.Tests.Xml.Sign
{
/// <summary>
/// Подпись и проверка подписи запроса к сервису СМЭВ (Система межведомственного электронного взаимодействия).
/// </summary>
/// <remarks>
/// Тест создает запрос к сервису СМЭВ, подписывает определенную часть данного запроса с использованием сертификата,
/// а затем проверяет полученную цифровую подпись.
/// </remarks>
[TestFixture(Description = "Подпись и проверка подписи запроса к сервису СМЭВ (Система межведомственного электронного взаимодействия)")]
public sealed class SignedXmlSmevTest
{
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";
[Test]
public void ShouldSignXml()
{
// Given
var signingCertificate = TestCertificates.GetCertificate();
var smevRequest = CreateSmevRequest();
// When
var signedXmlDocument = SignSmevRequest(smevRequest, signingCertificate);
// Then
Assert.IsTrue(VerifySmevRequestSignature(signedXmlDocument));
}
private static XmlDocument CreateSmevRequest()
{
var document = new XmlDocument();
document.LoadXml(Resources.SmevExample);
return document;
}
private static XmlDocument SignSmevRequest(XmlDocument smevRequest, X509Certificate2 signingCertificate)
{
// Создание подписчика XML-документа
var signedXml = new GostSignedXml(smevRequest) { GetIdElementHandler = GetSmevIdElement };
// Установка ключа для создания подписи
signedXml.SetSigningCertificate(signingCertificate);
// Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования ГОСТ Р 34.11-94 (в соответствии с методическими рекомендациями СМЭВ)
var dataReference = new Reference { Uri = "#body", DigestMethod = GostSignedXml.XmlDsigGost3411ObsoleteUrl };
// Метод преобразования, применяемый к данным перед их подписью (в соответствии с методическими рекомендациями СМЭВ)
var dataTransform = new XmlDsigExcC14NTransform();
dataReference.AddTransform(dataTransform);
// Установка ссылки на узел
signedXml.AddReference(dataReference);
// Установка алгоритма нормализации узла SignedInfo (в соответствии с методическими рекомендациями СМЭВ)
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
// Установка алгоритма подписи ГОСТ Р 34.10-2001 (в соответствии с методическими рекомендациями СМЭВ)
signedXml.SignedInfo.SignatureMethod = GostSignedXml.XmlDsigGost3410ObsoleteUrl;
// Вычисление подписи
signedXml.ComputeSignature();
// Получение XML-представления подписи
var signatureXml = signedXml.GetXml();
// Добавление подписи в исходный документ
smevRequest.GetElementsByTagName("ds:Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignatureValue")[0], true));
smevRequest.GetElementsByTagName("ds:Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignedInfo")[0], true));
smevRequest.GetElementsByTagName("wsse:BinarySecurityToken")[0].InnerText = Convert.ToBase64String(signingCertificate.RawData);
return smevRequest;
}
private static bool VerifySmevRequestSignature(XmlDocument signedSmevRequest)
{
// Создание подписчика 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));
// Проверка подписи
return signedXml.CheckSignature(signingCertificate.GetPublicKeyAlgorithm());
}
}
}
return false;
}
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;
}
}
}