-
Notifications
You must be signed in to change notification settings - Fork 44
Open
Description
Доброго дня!
Спасибо за продукт! Очень выручаете!
Хотел попросить рассмотреть возможность поддержки работы с префиксом на блок Signature лично столкнулся с проблемой на примере сервиса ГИИС ДМДК https://dmdk.ru они отступают от стандарта и требуют префикс причем только "ds" пока решил временным костылём но хочется видеть интегрированное в библиотеку, более изящное и лаконичное решение так как не имею опыта работы с xml прикладываю то, что у меня работает.
Работающий код:
`
public static void SignDmdkXml(string requestFileName, string requestSignedFileName,
X509Certificate2 certificate, bool saveFormat = true)
{
// Подгружаем документ
var xdoc = new XmlDocument
{
PreserveWhitespace = saveFormat
};
xdoc.Load(requestFileName);
// Создание подписчика XML-документа
var signedXml = new PrefixedSignedXml(xdoc,"ds")
{
// Установка ключа для создания подписи
SigningKey = certificate.PrivateKey,
SignedInfo =
{
// Установка алгоритма нормализации узла SignedInfo (в соответствии с методическими рекомендациями СМЭВ)
CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl,
// Установка алгоритма хэширования (в соответствии с методическими рекомендациями СМЭВ)
SignatureMethod = CPSignedXml.XmlDsigGost3410_2012_256Url
}
};
// Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования
var dataReference = new Reference
{
Uri = "#body",
DigestMethod = CPSignedXml.XmlDsigGost3411_2012_256Url
};
// Метод преобразования, применяемый к данным перед их подписью (в соответствии с методическими рекомендациями СМЭВ)
dataReference.AddTransform(new XmlDsigExcC14NTransform());
dataReference.AddTransform(new XmlDsigSmevTransform());
signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform");
// Установка ссылки на узел
signedXml.AddReference(dataReference);
// Установка информации о сертификате, который использовался для создания подписи
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(certificate));
signedXml.KeyInfo = keyInfo;
// Вычисление подписи
signedXml.ComputeSignature();
// Получение XML-представления подписи
var signatureXml = signedXml.GetXml();
//// Добавление подписи в исходный документ
xdoc.GetElementsByTagName("ns:CallerSignature")[0].AppendChild(xdoc.ImportNode(signatureXml, true));
// Охраняем документ в выходной файл
if (!saveFormat)
{
var settings = new XmlWriterSettings
{
Indent = false,
NewLineChars = Empty
};
using var writer = XmlWriter.Create(requestSignedFileName, settings);
xdoc.Save(writer);
}
else
xdoc.Save(requestSignedFileName);
}
}
`
Использую обвертку над XmlSigned:
`
///
/// Thx https://stackoverflow.com/a/12343267
///
public class PrefixedSignedXml : SignedXml
{
private readonly string _prefix;
public PrefixedSignedXml(XmlDocument document, string prefix)
: base(document)
{
_prefix = prefix;
}
public void ComputeSignature()
{
BuildDigestedReferences();
var signingKey = SigningKey;
if (signingKey == null)
{
throw new CryptographicException("Cryptography_Xml_LoadKeyFailed");
}
if (SignedInfo.SignatureMethod == null)
{
if (signingKey is not DSA)
{
if (signingKey is not RSA)
{
throw new CryptographicException("Cryptography_Xml_CreatedKeyFailed");
}
SignedInfo.SignatureMethod ??= "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
}
else
{
SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
}
}
if (CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) is not SignatureDescription description)
{
throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated");
}
var hash = description.CreateDigest();
if (hash == null)
{
throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed");
}
GetC14NDigest(hash, _prefix);
m_signature.SignatureValue = description.CreateFormatter(signingKey).CreateSignature(hash);
}
public new XmlElement GetXml()
{
var e = base.GetXml();
SetPrefix(_prefix, e);
return e;
}
//Отражательно вызывать закрытый метод SignedXml.BuildDigestedReferences
private void BuildDigestedReferences()
{
var t = typeof(SignedXml);
var m = t.GetMethod("BuildDigestedReferences", BindingFlags.NonPublic | BindingFlags.Instance);
m?.Invoke(this, new object[] { });
}
private void GetC14NDigest(HashAlgorithm hash, string prefix)
{
//string securityUrl = (this.m_containingDocument == null) ? null : this.m_containingDocument.BaseURI;
//XmlResolver xmlResolver = new XmlSecureResolver(new XmlUrlResolver(), securityUrl);
var document = new XmlDocument
{
PreserveWhitespace = true
};
var e = SignedInfo.GetXml();
document.AppendChild(document.ImportNode(e, true));
//CanonicalXmlNodeList namespaces = (this.m_context == null) ? null : Utils.GetPropagatedAttributes(this.m_context);
//Utils.AddNamespaces(document.DocumentElement, namespaces);
var canonicalizationMethodObject = SignedInfo.CanonicalizationMethodObject;
//canonicalizationMethodObject.Resolver = xmlResolver;
//canonicalizationMethodObject.BaseURI = securityUrl;
SetPrefix(prefix, document.DocumentElement); //мы устанавливаем префикс перед вычислением хеша (иначе подпись не будет действительной)
canonicalizationMethodObject.LoadInput(document);
canonicalizationMethodObject.GetDigestedOutput(hash);
}
private static void SetPrefix(string prefix, XmlNode node)
{
foreach (XmlNode n in node.ChildNodes)
SetPrefix(prefix, n);
node.Prefix = prefix;
}
}
`
Metadata
Metadata
Assignees
Labels
No labels