Fix signature validation

This commit is contained in:
2025-10-02 17:23:12 +09:00
parent 606b05ae76
commit 795b633a39
2 changed files with 242 additions and 5 deletions

View File

@ -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#";
/// <summary>
/// OID алгоритма открытого ключа/цифровой подписи ГОСТ Р 34.10-2001
/// </summary>
private const string OID_CP_GOST_R3410EL = "1.2.643.2.2.19";
/// <summary>
/// OID алгоритма открытого ключа/цифровой подписи ГОСТ Р 34.10-2012 256
/// </summary>
private const string OID_CP_GOST_R3410_12_256 = "1.2.643.7.1.1.1.1";
/// <summary>
/// OID алгоритма открытого ключа/цифровой подписи ГОСТ Р 34.10-2012 512
/// </summary>
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=");
}
}
}