Add project
Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
38
Hcs.Client/GostXades/Helpers/ArrayHelper.cs
Normal file
38
Hcs.Client/GostXades/Helpers/ArrayHelper.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class ArrayHelper
|
||||
{
|
||||
public static bool AreEquals(byte[] first, byte[] second)
|
||||
{
|
||||
return AreEquals(first, second, (x, y) => x.Equals(y));
|
||||
}
|
||||
|
||||
public static bool AreEquals(string[] first, string[] second)
|
||||
{
|
||||
return AreEquals(first, second, (x, y) => string.Equals(x, y, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
private static bool AreEquals<T>(T[] first, T[] second, Func<T, T, bool> comparator)
|
||||
{
|
||||
if (first == second)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (first.Length != second.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < first.Length; i++)
|
||||
{
|
||||
var equals = comparator.Invoke(first[i], second[i]);
|
||||
if (!equals)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Hcs.Client/GostXades/Helpers/CertificateHelper.cs
Normal file
67
Hcs.Client/GostXades/Helpers/CertificateHelper.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class CertificateHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение сертификата из личного локального хранилища по отпечатку
|
||||
/// </summary>
|
||||
/// <param name="thumbprint">Отпечаток требуемого сертификата</param>
|
||||
/// <returns>Сертификат с нужным отпечатком</returns>
|
||||
public static X509Certificate2 GetCertificateByThumbprint(string thumbprint)
|
||||
{
|
||||
var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
|
||||
|
||||
try
|
||||
{
|
||||
certificateStore.Open(OpenFlags.ReadOnly);
|
||||
var certificateCollection = certificateStore.Certificates
|
||||
.Cast<X509Certificate2>()
|
||||
.Where(i => string.Equals(i.Thumbprint, thumbprint, StringComparison.InvariantCultureIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
if (!certificateCollection.Any())
|
||||
{
|
||||
throw new ArgumentException("Некорректный отпечаток сертификата");
|
||||
}
|
||||
|
||||
var activeCertificates = certificateCollection.Where(i => DateTime.Parse(i.GetEffectiveDateString()) <= DateTime.Now &&
|
||||
DateTime.Now <= DateTime.Parse(i.GetExpirationDateString()))
|
||||
.ToArray();
|
||||
if (activeCertificates.Any())
|
||||
{
|
||||
return activeCertificates[0];
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Сертификат с указанным отпечатком {thumbprint} недействителен");
|
||||
}
|
||||
finally
|
||||
{
|
||||
certificateStore.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение сертификатов из локального хранилища текущего пользователя
|
||||
/// </summary>
|
||||
/// <returns>Сертификаты из локального хранилища текущего пользователя</returns>
|
||||
public static IEnumerable<X509Certificate2> GetCertificates()
|
||||
{
|
||||
var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
|
||||
|
||||
try
|
||||
{
|
||||
certificateStore.Open(OpenFlags.ReadOnly);
|
||||
return certificateStore.Certificates.OfType<X509Certificate2>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
certificateStore.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Hcs.Client/GostXades/Helpers/CollectionHelper.cs
Normal file
13
Hcs.Client/GostXades/Helpers/CollectionHelper.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class CollectionHelper
|
||||
{
|
||||
public static bool IsNotEmpty(this IEnumerable enumerable)
|
||||
{
|
||||
return enumerable != null && enumerable.OfType<object>().Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Hcs.Client/GostXades/Helpers/ConvertHelper.cs
Normal file
12
Hcs.Client/GostXades/Helpers/ConvertHelper.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class ConvertHelper
|
||||
{
|
||||
public static string BigIntegerToHex(string str)
|
||||
{
|
||||
return BigInteger.Parse(str).ToString("X");
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Hcs.Client/GostXades/Helpers/DateTimeHelper.cs
Normal file
14
Hcs.Client/GostXades/Helpers/DateTimeHelper.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class DateTimeHelper
|
||||
{
|
||||
public static DateTimeOffset ToDateTimeOffset(this DateTime dateTime, int timeZoneOffsetMinutes = 0)
|
||||
{
|
||||
var shiftedDateTime = dateTime.AddMinutes(timeZoneOffsetMinutes);
|
||||
var unspecifiedDateTime = DateTime.SpecifyKind(shiftedDateTime, DateTimeKind.Unspecified);
|
||||
return new DateTimeOffset(unspecifiedDateTime, new TimeSpan(0, timeZoneOffsetMinutes, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Hcs.Client/GostXades/Helpers/EnumerableHelper.cs
Normal file
15
Hcs.Client/GostXades/Helpers/EnumerableHelper.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class EnumerableHelper
|
||||
{
|
||||
public static bool AreSequenceEquals(IEnumerable<string> first, IEnumerable<string> second)
|
||||
{
|
||||
var sortedFirst = first.OrderBy(x => x).ToArray();
|
||||
var sortedSecond = second.OrderBy(x => x).ToArray();
|
||||
return ArrayHelper.AreEquals(sortedFirst, sortedSecond);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Hcs.Client/GostXades/Helpers/GostHashAlgorithmHelper.cs
Normal file
23
Hcs.Client/GostXades/Helpers/GostHashAlgorithmHelper.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using GostCryptography.Config;
|
||||
using System;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class GostHashAlgorithmHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Рассчитать хэш
|
||||
/// </summary>
|
||||
/// <param name="cryptoProviderType">Тип криптопровайдера</param>
|
||||
/// <param name="bytes"></param>
|
||||
/// <returns></returns>
|
||||
public static string ComputeHash(CryptoProviderTypeEnum cryptoProviderType, byte[] bytes)
|
||||
{
|
||||
byte[] hashValue;
|
||||
GostCryptoConfig.ProviderType = (GostCryptography.Base.ProviderType)cryptoProviderType;
|
||||
var hashAlgorithm = new GostCryptography.Gost_R3411.Gost_R3411_2012_512_HashAlgorithm();
|
||||
hashValue = hashAlgorithm.ComputeHash(bytes);
|
||||
return BitConverter.ToString(hashValue).Replace("-", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Hcs.Client/GostXades/Helpers/KeyInfoHelper.cs
Normal file
28
Hcs.Client/GostXades/Helpers/KeyInfoHelper.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class KeyInfoHelper
|
||||
{
|
||||
public static KeyInfo Create(X509Certificate2 certificate)
|
||||
{
|
||||
var xmlDocument = new XmlDocument();
|
||||
|
||||
var x509DataElement = xmlDocument.CreateElement("ds", "X509Data", KeyInfoNamespace);
|
||||
var x509CertificateElement = xmlDocument.CreateElement("ds", "X509Certificate", KeyInfoNamespace);
|
||||
x509CertificateElement.InnerText = Convert.ToBase64String(certificate.GetRawCertData());
|
||||
|
||||
x509DataElement.AppendChild(x509CertificateElement);
|
||||
|
||||
var keyInfo = new KeyInfo();
|
||||
keyInfo.AddClause(new KeyInfoNode(x509DataElement));
|
||||
|
||||
return keyInfo;
|
||||
}
|
||||
|
||||
private const string KeyInfoNamespace = "http://www.w3.org/2000/09/xmldsig#";
|
||||
}
|
||||
}
|
||||
74
Hcs.Client/GostXades/Helpers/X509NameHelper.cs
Normal file
74
Hcs.Client/GostXades/Helpers/X509NameHelper.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class X509NameHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Исправить строку X509IssuerName для рукожопых пейсателей из Ланита
|
||||
/// </summary>
|
||||
/// <param name="x509Name">Исходная строка из сертификата</param>
|
||||
/// <returns>Исправленная строка, чтобы ее понимал сервер ГИС ЖКХ</returns>
|
||||
public static string ToX509IssuerName(this X509Name x509Name)
|
||||
{
|
||||
string x509IssuerName = x509Name.ToString();
|
||||
var pairs = x509IssuerName
|
||||
.Replace("\\,", "^_^")
|
||||
.Split(',')
|
||||
.Select(part => part.Split('='))
|
||||
.Select(lrParts => new ReplacementPair
|
||||
{
|
||||
Key = lrParts[0],
|
||||
Value = lrParts.Length == 2 ? lrParts[1] : string.Empty
|
||||
}).ToList();
|
||||
|
||||
var nCount = pairs.Count;
|
||||
var result = new StringBuilder();
|
||||
var i = 0;
|
||||
foreach (var pair in pairs)
|
||||
{
|
||||
switch (pair.Key.ToLower())
|
||||
{
|
||||
case "t":
|
||||
case "title":
|
||||
pair.Key = "2.5.4.12";
|
||||
break;
|
||||
|
||||
case "g":
|
||||
case "givenname":
|
||||
pair.Key = "2.5.4.42";
|
||||
break;
|
||||
case "e":
|
||||
pair.Key = "1.2.840.113549.1.9.1";
|
||||
break;
|
||||
case "sn":
|
||||
case "surname":
|
||||
pair.Key = "2.5.4.4";
|
||||
break;
|
||||
|
||||
case "ou":
|
||||
case "orgunit":
|
||||
pair.Key = "2.5.4.11";
|
||||
break;
|
||||
|
||||
case "unstructured-name":
|
||||
case "unstructuredname":
|
||||
pair.Key = "1.2.840.113549.1.9.2";
|
||||
break;
|
||||
}
|
||||
|
||||
result.Append($"{pair.Key}={pair.Value}{(i != (nCount - 1) ? ", " : string.Empty)}");
|
||||
i++;
|
||||
}
|
||||
return result.ToString().Replace("^_^", "\\,");
|
||||
}
|
||||
}
|
||||
|
||||
internal class ReplacementPair
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
16
Hcs.Client/GostXades/Helpers/XadesSignedXmlHelper.cs
Normal file
16
Hcs.Client/GostXades/Helpers/XadesSignedXmlHelper.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using Microsoft.Xades;
|
||||
using System.Xml;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class XadesSignedXmlHelper
|
||||
{
|
||||
public static void InjectSignatureTo(this XadesSignedXml signedXml, XmlDocument originalDoc)
|
||||
{
|
||||
var signatureElement = signedXml.GetXml();
|
||||
var importSignatureElement = originalDoc.ImportNode(signatureElement, true);
|
||||
var signedDataContainer = signedXml.GetIdElement(originalDoc, signedXml.SignedElementId);
|
||||
signedDataContainer.InsertBefore(importSignatureElement, signedDataContainer.FirstChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Hcs.Client/GostXades/Helpers/XmlDocumentHelper.cs
Normal file
77
Hcs.Client/GostXades/Helpers/XmlDocumentHelper.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
|
||||
namespace Hcs.GostXades.Helpers
|
||||
{
|
||||
public static class XmlDocumentHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> XmlDocument <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public static XmlDocument Create(string xmlData)
|
||||
{
|
||||
var xmlDocument = new XmlDocument { PreserveWhitespace = true };
|
||||
try
|
||||
{
|
||||
xmlDocument.LoadXml(xmlData);
|
||||
}
|
||||
catch (XmlException xmlEx)
|
||||
{
|
||||
throw new InvalidOperationException($"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> xml <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {xmlEx.Message}", xmlEx);
|
||||
}
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> XmlDocument <20><> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public static XmlDocument Load(string pathName)
|
||||
{
|
||||
var xmlDocument = new XmlDocument { PreserveWhitespace = true };
|
||||
try
|
||||
{
|
||||
xmlDocument.Load(pathName);
|
||||
}
|
||||
catch (XmlException xmlEx)
|
||||
{
|
||||
throw new InvalidOperationException($"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> xml <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {xmlEx.Message}", xmlEx);
|
||||
}
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> XmlDocument
|
||||
/// </summary>
|
||||
public static XmlNamespaceManager CreateNamespaceManager(this XmlDocument xml)
|
||||
{
|
||||
var manager = new XmlNamespaceManager(xml.NameTable);
|
||||
foreach (var name in GetNamespaceDictionary(xml))
|
||||
{
|
||||
manager.AddNamespace(name.Key, name.Value);
|
||||
}
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
private static IDictionary<string, string> GetNamespaceDictionary(this XmlDocument xml)
|
||||
{
|
||||
var nameSpaceList = xml.SelectNodes(@"//namespace::*[not(. = ../../namespace::*)]").OfType<XmlNode>();
|
||||
return nameSpaceList.Distinct(new LocalNameComparer()).ToDictionary(xmlNode => xmlNode.LocalName, xmlNode => xmlNode.Value);
|
||||
}
|
||||
|
||||
private class LocalNameComparer : IEqualityComparer<XmlNode>
|
||||
{
|
||||
public bool Equals(XmlNode x, XmlNode y)
|
||||
{
|
||||
return x.LocalName == y.LocalName;
|
||||
}
|
||||
|
||||
public int GetHashCode(XmlNode obj)
|
||||
{
|
||||
return obj.LocalName.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user