Принимающая сторона не может проверить подписанное сообщение XML

Я пытаюсь подписать XML с помощью C # в соответствии со спецификацией, предоставленной нам для нашего тестового приложения. Мы должны:

  1. Канонизируйте сообщение.
  2. Используйте алгоритм дайджеста, чтобы создать дайджест всего сообщения.
  3. Добавьте дайджест в элемент «Информация с подписью».
  4. Канонизировать подписанную информацию.
  5. Введите закрытый ключ и канонизированную подписанную информацию в указанный алгоритм подписи для создания цифровой подписи.
  6. Добавьте сгенерированную цифровую подпись к элементу подписи.

Это то, что у меня есть сейчас.

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>

Изменить: если кто-то создаст пример, используя приведенную выше информацию для подписи, я приму ответ.


person Jimenemex    schedule 17.03.2020    source источник
comment
Может ли принимающая сторона проверить вашу цепочку сертификатов? Есть ли у них сертификат эмитента (главный центр сертификации) в их надежном хранилище сертификатов?   -  person Oguz Ozgul    schedule 17.03.2020
comment
@OguzOzgul Да.   -  person Jimenemex    schedule 17.03.2020
comment
Ошибка указывает на то, что параметры шифрования не совпадают с параметрами дешифрования. Таким образом, вы должны сравнить варианты с обеих сторон и добиться от них согласия. Просто взглянуть на код шифрования не поможет. Fiddler покажет параметры, используемые на стороне отправки, которые подтвердят, что вы отправляете действительный подписанный xml, но не будут отображать параметры приема.   -  person jdweng    schedule 17.03.2020
comment
@jdweng Не уверен, что вы имеете в виду   -  person Jimenemex    schedule 17.03.2020
comment
Это как если бы один человек говорил по-английски, а другой по-французски. Оба говорят правильно, просто не понимают друг друга.   -  person jdweng    schedule 17.03.2020
comment
@Jimenemex 1. Можете ли вы проверить подпись на своей стороне? 2. Можете ли вы предоставить код, проверяющий подпись на другой стороне? 3. Можете ли вы добавить в сообщение образец XML-файла, подписанный вашим Sign методом?   -  person Iliar Turdushev    schedule 24.03.2020
comment
Как сказал @IliarTurdushev, было бы важно увидеть образец подписанного XML-документа именно в том виде, в котором он отправляется другой стороне (пробелы имеют значение). Еще одна мысль заключается в том, что вам действительно не нужно добавлять префикс ds. Например, я создаю Signature XML-документы без префикса ds, и они проверяются как подписи XAdES с помощью ETSI Conformance Checker.   -  person Thomas Barnekow    schedule 26.03.2020
comment
@Jimenemex Что делает ваше пользовательское преобразование XmlDsigC14N11Transform? Применяет ли принимающая сторона это преобразование при проверке подписи? Можно ли отключить это преобразование и проверить, может ли принимающая сторона проверить подпись без этого преобразования?   -  person Iliar Turdushev    schedule 27.03.2020
comment
@IliarTurdushev Это настоящий XmlDsigC14N11Transform, который .NET, похоже, не поддерживает. Портировали с Java. Принимающая сторона выполняет это преобразование в соответствии со своей документацией. Исключение этого преобразования не приводит к тому, что проверка работает.   -  person Jimenemex    schedule 27.03.2020
comment
@Jimenemex У меня есть последнее предположение, почему проверка подписи может завершиться ошибкой на принимающей стороне. Это Encoding. Вы должны убедиться, что отправляющая и получающая стороны используют одну и ту же кодировку. Если обе стороны используют UTF-8, убедитесь, что обе стороны используют UTF-8 с или без спецификации. Если принимающая сторона не указывает кодировку для чтения сообщения, посоветуйте им использовать метод (XmlDocument.Load(XmlReader)) (в случае, если они используют .NET). Эта перегрузка метода XmlDocument.Load позволяет указать кодировку XML-документа для чтения.   -  person Iliar Turdushev    schedule 28.03.2020
comment
a) У вас нет ссылки на элемент KeyInfo в SignedInfo b) KeyInfo в соответствии со стандартом ISO20022 должен иметь идентификатор c) KeyInfo должен содержать X509Certificate с открытым ключом   -  person Ulterior    schedule 13.06.2020


Ответы (1)


Чтобы исправить ситуацию на стороне получателя, мы заменяем S = на ST = в узле X509SubjectName.

person cderrick    schedule 16.06.2020