Fix signature validation
This commit is contained in:
@ -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)
|
||||
{
|
||||
|
||||
240
Hcs.Broker/Api/Request/SignedXml.cs
Normal file
240
Hcs.Broker/Api/Request/SignedXml.cs
Normal 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=");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user