Files
hcs/Hcs.Broker/Api/Request/SignedXml.cs

241 lines
8.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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=");
}
}
}