From 795b633a39a143306357df352f308b72fea8a380 Mon Sep 17 00:00:00 2001 From: "HOME-LAPTOP\\kshkulev" Date: Thu, 2 Oct 2025 17:23:12 +0900 Subject: [PATCH] Fix signature validation --- .../Request/GostSigningMessageInspector.cs | 7 +- Hcs.Broker/Api/Request/SignedXml.cs | 240 ++++++++++++++++++ 2 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 Hcs.Broker/Api/Request/SignedXml.cs diff --git a/Hcs.Broker/Api/Request/GostSigningMessageInspector.cs b/Hcs.Broker/Api/Request/GostSigningMessageInspector.cs index dc1b7ae..439a456 100644 --- a/Hcs.Broker/Api/Request/GostSigningMessageInspector.cs +++ b/Hcs.Broker/Api/Request/GostSigningMessageInspector.cs @@ -116,7 +116,7 @@ namespace Hcs.Broker.Api.Request var keyInfo = new CpKeyInfo(); keyInfo.AddClause(new CpKeyInfoX509Data(certificate)); - var signedXml = new CpXadesSignedXml(doc) + var signedXml = new SignedXml(doc) { SigningKey = key, KeyInfo = keyInfo @@ -131,9 +131,6 @@ namespace Hcs.Broker.Api.Request var signTransform = new CpXmlDsigEnvelopedSignatureTransform(); reference.AddTransform(signTransform); - var c14nTransform = new CpXmlDsigC14NTransform(); - reference.AddTransform(c14nTransform); - signedXml.AddReference(reference); if (useDsPrefix) @@ -147,7 +144,7 @@ namespace Hcs.Broker.Api.Request var element = doc.SelectNodes("//*[@Id='" + Constants.SIGNED_XML_ELEMENT_ID + "']")[0]; var xmlDigitalSignature = signedXml.GetXml(); - element.AppendChild(doc.ImportNode(xmlDigitalSignature, true)); + element.PrependChild(doc.ImportNode(xmlDigitalSignature, true)); if (doc.FirstChild is XmlDeclaration) { diff --git a/Hcs.Broker/Api/Request/SignedXml.cs b/Hcs.Broker/Api/Request/SignedXml.cs new file mode 100644 index 0000000..0dcb8e5 --- /dev/null +++ b/Hcs.Broker/Api/Request/SignedXml.cs @@ -0,0 +1,240 @@ +using CryptoPro.Security.Cryptography; +using CryptoPro.Security.Cryptography.X509Certificates; +using CryptoPro.Security.Cryptography.Xml; +using System.Globalization; +using System.Numerics; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Xml; + +namespace Hcs.Broker.Api.Request +{ + internal class SignedXml(XmlDocument document) : CpXadesSignedXml(document) + { + private const string XADES_141_NAMESPACE_URL = "http://uri.etsi.org/01903/v1.4.1#"; + + /// + /// OID алгоритма открытого ключа/цифровой подписи ГОСТ Р 34.10-2001 + /// + private const string OID_CP_GOST_R3410EL = "1.2.643.2.2.19"; + + /// + /// OID алгоритма открытого ключа/цифровой подписи ГОСТ Р 34.10-2012 256 + /// + private const string OID_CP_GOST_R3410_12_256 = "1.2.643.7.1.1.1.1"; + + /// + /// OID алгоритма открытого ключа/цифровой подписи ГОСТ Р 34.10-2012 512 + /// + private const string OID_CP_GOST_R3410_12_512 = "1.2.643.7.1.1.1.2"; + + protected override void AddXadesProperties( + CpX509Certificate2 signingCertificate, + DateTime time, + string signatureId, + string objectId, + string? xmlDSigPrefix, + XadesPropertiesFlags xadesProperties) + { + if (_containingDocument == null) + { + throw new InvalidOperationException("XmlDocument is null"); + } + + var useCertificateV2 = xadesProperties.HasFlag( + XadesPropertiesFlags.UseSigningCertificateV2 + ); + var useCertificateV1 = xadesProperties.HasFlag( + XadesPropertiesFlags.UseSigningCertificateV1 + ); + if ((useCertificateV2 && useCertificateV1) || (!useCertificateV2 && !useCertificateV1)) + { + throw new InvalidOperationException("Invalid flags"); + } + + var document = _containingDocument; + + var parametersSignature = new CpReference + { + Uri = $"#{objectId}", + Type = XmlDsigSignatureProperties, + DigestMethod = XmlDsigGost3411_2012_256Url, + }; + parametersSignature.AddTransform(new CpXmlDsigExcC14NTransform()); + + AddReference(parametersSignature); + + var qualifyingPropertiesNode = document.CreateElement( + XadesPrefix, + "QualifyingProperties", + XadesNamespaceUrl + ); + qualifyingPropertiesNode.SetAttribute("xmlns:xades141", XADES_141_NAMESPACE_URL); + qualifyingPropertiesNode.SetAttribute("Target", $"#{signatureId}"); + + var signedPropertiesNode = document.CreateElement( + XadesPrefix, + "SignedProperties", + XadesNamespaceUrl + ); + signedPropertiesNode.SetAttribute("Id", objectId); + + qualifyingPropertiesNode.AppendChild(signedPropertiesNode); + + var signedSignaturePropertiesNode = document.CreateElement( + XadesPrefix, + "SignedSignatureProperties", + XadesNamespaceUrl + ); + signedPropertiesNode.AppendChild(signedSignaturePropertiesNode); + + var signingTime = document.CreateElement(XadesPrefix, "SigningTime", XadesNamespaceUrl); + signingTime.InnerText = time.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); + + signedSignaturePropertiesNode.AppendChild(signingTime); + + var signingCertificateNodeName = useCertificateV2 + ? "SigningCertificateV2" + : "SigningCertificate"; + var signingCertificateNode = document.CreateElement( + XadesPrefix, + signingCertificateNodeName, + XadesNamespaceUrl + ); + + signedSignaturePropertiesNode.AppendChild(signingCertificateNode); + + var certNode = document.CreateElement(XadesPrefix, "Cert", XadesNamespaceUrl); + signingCertificateNode.AppendChild(certNode); + + var certDigestNode = document.CreateElement( + XadesPrefix, + "CertDigest", + XadesNamespaceUrl + ); + certNode.AppendChild(certDigestNode); + + var algIdString = signingCertificate.GetKeyAlgorithm(); + (bool isGost, string? gostDigestAlgorithm) = algIdString switch + { + OID_CP_GOST_R3410EL => (true, XmlDsigGost3411Url), + OID_CP_GOST_R3410_12_256 => ( + true, + XmlDsigGost3411_2012_256Url + ), + OID_CP_GOST_R3410_12_512 => ( + true, + XmlDsigGost3411_2012_512Url + ), + _ => (false, null), + }; + + var digestMethodAlgorithmAtribute = document.CreateAttribute("Algorithm"); + if (isGost) + { + digestMethodAlgorithmAtribute.InnerText = gostDigestAlgorithm!; + } + else + { + digestMethodAlgorithmAtribute.InnerText = XmlDsigSHA1Url; + } + + var digestMethod = document.CreateElement( + xmlDSigPrefix, + "DigestMethod", + XmlDsigNamespaceUrl + ); + digestMethod.Attributes.Append(digestMethodAlgorithmAtribute); + + certDigestNode.AppendChild(digestMethod); + + var digestValue = document.CreateElement( + xmlDSigPrefix, + "DigestValue", + XmlDsigNamespaceUrl + ); + + if (isGost) + { + var hash = + CpCryptoConfig.CreateFromName(gostDigestAlgorithm!) as HashAlgorithm + ?? throw new System.Exception( + $"Cannot find [{gostDigestAlgorithm}] alg in CpCryptoConfig!" + ); + using (hash) + { + digestValue.InnerText = Convert.ToBase64String( + hash.ComputeHash(signingCertificate.RawData) + ); + } + } + else + { + digestValue.InnerText = Convert.ToBase64String(signingCertificate.GetCertHash()); + } + + certDigestNode.AppendChild(digestValue); + + if (useCertificateV2) + { + var issuerSerialNode = document.CreateElement( + XadesPrefix, + "IssuerSerialV2", + XadesNamespaceUrl + ); + issuerSerialNode.InnerText = Convert.ToBase64String( + X509EncodeIssuerAndSerialHelper.EncodeIssuerAndSerial(signingCertificate) + ); + + certNode.AppendChild(issuerSerialNode); + } + else + { + var issuerName = signingCertificate.IssuerName.Decode(X500DistinguishedNameFlags.DoNotUseQuotes); + var x509IssuerNameNode = document.CreateElement( + xmlDSigPrefix, + "X509IssuerName", + XmlDsigNamespaceUrl + ); + x509IssuerNameNode.InnerText = GetOidRepresentation(issuerName); + + var issuerSerialNode = document.CreateElement( + XadesPrefix, + "IssuerSerial", + XadesNamespaceUrl + ); + issuerSerialNode.AppendChild(x509IssuerNameNode); + + var x509SerialNumber = document.CreateElement( + xmlDSigPrefix, + "X509SerialNumber", + XmlDsigNamespaceUrl + ); + x509SerialNumber.InnerText = BigInteger.Parse(signingCertificate.SerialNumber, NumberStyles.HexNumber).ToString(); + + issuerSerialNode.AppendChild(x509SerialNumber); + certNode.AppendChild(issuerSerialNode); + } + + var dataObject = new CpDataObject(); + dataObject.Data = qualifyingPropertiesNode.SelectNodes("."); + + AddObject(dataObject); + } + + private string GetOidRepresentation(string issuerName) + { + return issuerName + .Replace("\"", "\\\"") + .Replace("E=", "1.2.840.113549.1.9.1=") + .Replace("unstructuredName=", "1.2.840.113549.1.9.2=") + .Replace("ОГРН=", "1.2.643.100.1=") + .Replace("ИНН ЮЛ=", "1.2.643.100.4=") + .Replace("ИНН ФЛ=", "1.2.643.3.131.1.1=") + .Replace("ИНН=", "1.2.643.3.131.1.1=") + .Replace("СНИЛС=", "1.2.643.100.3=") + .Replace("ОГРНИП=", "1.2.643.100.5=") + .Replace("S=", "ST="); + } + } +}