Я пытаюсь подписать XML с помощью C # в соответствии со спецификацией, предоставленной нам для нашего тестового приложения. Мы должны:
- Канонизируйте сообщение.
- Используйте алгоритм дайджеста, чтобы создать дайджест всего сообщения.
- Добавьте дайджест в элемент «Информация с подписью».
- Канонизировать подписанную информацию.
- Введите закрытый ключ и канонизированную подписанную информацию в указанный алгоритм подписи для создания цифровой подписи.
- Добавьте сгенерированную цифровую подпись к элементу подписи.
Это то, что у меня есть сейчас.
public static XmlElement Sign(XmlDocument msgDoc)
{
XmlDsigExcC14NTransform transform = new XmlDsigExcC14NTransform();
transform.LoadInput(msgDoc);
msgDoc.Load(transform.GetOutput() as Stream);
var signedXml = new SignedXml(msgDoc)
{
SigningKey = Certificate.GetRSAPrivateKey(),
};
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
var reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform(true));
reference.AddTransform(new XmlDsigC14N11Transform()); // Custom transform
reference.Uri = string.Empty;
reference.DigestMethod = SignedXml.XmlDsigSHA256Url;
signedXml.SignedInfo.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
var keyInfoData = new KeyInfoX509Data();
keyInfoData.AddIssuerSerial(CertManager.Certificate.Issuer, CertManager.Certificate.SerialNumber);
keyInfoData.AddSubjectName(CertManager.Certificate.Subject);
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();
XmlElement signature = signedXml.GetXml();
// This part until the return was done to ensure we get the 'ds' prefix.
// Code taken from: https://stackoverflow.com/questions/30579938/generate-digital-signature-but-with-a-specific-namespace-prefix-ds
SetPrefix("ds", signature);
signedXml.LoadXml(signature);
signedXml.SignedInfo.References.Clear();
signedXml.ComputeSignature();
ReplaceSignature(signature, Convert.ToBase64String(signedXml.SignatureValue));
XmlNode signatureElement = msgDoc.ImportNode(signature, true);
return msgDoc.DocumentElement.InsertAfter(msgDoc.ImportNode(signature, true), msgDoc.DocumentElement.FirstChild) as XmlElement;
}
Алгоритм дайджеста: http://www.w3.org/2001/04/xmlenc#sha256
Алгоритм канонизации: http://www.w3.org/2001/10/xml-exc-c14n#
Мы используем два преобразования: http://www.w3.org/2000/09/xmldsig#enveloped-signature и http://www.w3.org/2006/12/xml-c14n11
Я включил трассировку на другой стороне, которая должна проверять сообщение, и, похоже, это единственное место, где что-то не получается в журнале трассировки:
[SignedXml # 0071d445, VerificationFailure] Проверка не прошла проверку SignedInfo.
Я удостоверился, что Certificate
, используемый в процессе подписания, является моим частным сертификатом, а другая сторона использует открытый сертификат для процесса проверки.
Что еще мне не хватает?
Редактировать:
Мы можем проверять сообщения, которые получаем с их стороны. Я не могу предоставить какой-либо код того, как они проверяют сообщения, потому что он нам не предоставлен.
Это пример того, что мы отправляем:
<Message xmlns="urn:tch">
<AppHdr>
<head:Fr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
<head:ID>
<head:MemberId>1234245</head:MemberId>
</head:ID>
</head:Fr>
<head:To xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
<head:ID>
<head:MemberId>123345345</head:MemberId>
</head:ID>
<head:Date xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">2020-03-16T22:03:24</head:Date>
<head:Sgntr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>fV61VLaSYGyW+G+LxZaLfGdOlAVmpJvusoJ792IKblw=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>xlg1Q4hdQoCo+x4rJKWn1UwLwdshonx0dg5Z0bIAsFuBWOJGyVescQBFEZEbUHcgLq2TQZT6PBhH3F2RR4aYTnc9IY0mHRq5rJEpVfXnQZdwCw7SIhkMMIOi5rAgQ5gdLmQlbLWFm8V4+1DTE7QWiCALEkarJQcdU4n9E2rGrSM48H1NFHHC+m8J5eHcGFyRcBwSF712ihGDNvweGhwneR4JeGxyQ3Dc1pSkzkr0oOJDY0vgwIuMZIMvl6Fh98D3QByDadZqFah88uv+TWZy01B9rdfhgCP7gdeiP9fof90jnitQ4c/3XksjieLbWQxWmQ1TPoRQswDuXf731T6kmw==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=ABC, DC=AAA, DC=BBB, DC=CCC</ds:X509IssuerName>
<ds:X509SerialNumber>75822323454364025267732697561489775234425345</ds:X509SerialNumber>
</ds:X509IssuerSerial>
<ds:X509SubjectName>[email protected], CN=ABC.com, OU=Internet Services, O=AAA, L=Someplace, S=somewhere, C=US</ds:X509SubjectName>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</head:Sgntr>
</AppHdr>
<TestMessage>
<mr:zzzz.002.001.01 xmlns:mr="urn:iso:std:iso:20022:tech:xsd:zzzz.002.001.01">
<mr:Ref>
<mr:Ref>20200316220315134567890122203156779</mr:Ref>
</mr:Ref>
</TestMessage>
</Message>
Изменить: если кто-то создаст пример, используя приведенную выше информацию для подписи, я приму ответ.
Sign
методом? - person Iliar Turdushev   schedule 24.03.2020ds
. Например, я создаюSignature
XML-документы без префиксаds
, и они проверяются как подписи XAdES с помощью ETSI Conformance Checker. - person Thomas Barnekow   schedule 26.03.2020XmlDsigC14N11Transform
? Применяет ли принимающая сторона это преобразование при проверке подписи? Можно ли отключить это преобразование и проверить, может ли принимающая сторона проверить подпись без этого преобразования? - person Iliar Turdushev   schedule 27.03.2020XmlDsigC14N11Transform
, который .NET, похоже, не поддерживает. Портировали с Java. Принимающая сторона выполняет это преобразование в соответствии со своей документацией. Исключение этого преобразования не приводит к тому, что проверка работает. - person Jimenemex   schedule 27.03.2020Encoding
. Вы должны убедиться, что отправляющая и получающая стороны используют одну и ту же кодировку. Если обе стороны используют UTF-8, убедитесь, что обе стороны используют UTF-8 с или без спецификации. Если принимающая сторона не указывает кодировку для чтения сообщения, посоветуйте им использовать метод (XmlDocument.Load(XmlReader)
) (в случае, если они используют.NET
). Эта перегрузка методаXmlDocument.Load
позволяет указать кодировку XML-документа для чтения. - person Iliar Turdushev   schedule 28.03.2020