Автор: oleg_kashin В целом ошибка та же, проблема вероятно в том же -и наверно все так же в каноникализации.
Сидел я тут разбирался и прошел неожиданный ответ от поддержки ГИС ЖКХ, который вообще в ступор поставил:
Цитата:"Обращаем Ваше внимание, что данная ошибка возникает в результате того, что подпись запроса вычислена некорректна: неверно рассчитано значение "DigestValue" в группе тегов "SigningCertificate"."
Я правильно понимаю что это они бред написали или действительно что-то может быть не так:
1)Вообще просто проверить расчет хэша в этом тэге - что записано в теге X509Certificate после декодировки в base64 взять хэш по urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256 и оно должно совпадать со значением DigestValue.
Ну и собственно все совпадает - совпадает и на пример-запросе от поддержки ГИС ЖКХ
2)"two_oceans" то же это считал...
Кстати этот их ответ про "DigestValue" в группе тегов "SigningCertificate" был после уточняющего вопроса по переписке на их первоначальный ответ:
Цитата:"SGN000032:Signature verification failed: org.apache.xml.security.exceptions.XMLSecurityException: Invalid digest of reference #xmldsig-8ac47b3d-c066-4507-a734-57fa20918b4b-signedprops
Связанная с этим ошибка «AUT011005 Ошибка формата подписи запроса» возникает в результате того, что подпись запроса не верна: неверно рассчитано значение "DigestValue" . Также просьба убедиться, что текст запроса не был изменён после его подписания. Для успешной отправки запроса не рекомендуется вносить изменения в подписанный запрос."
Я как бы возмутился что в примере, который я им отправлял не было reference с xmldsig-8ac47b3d-c066-4507-a734-57fa20918b4b-signedprops.
По порядку: по идее подпись проверяется каскадом - а) проверяется SignatureValue с SignedInfo, если неверно выдается ошибка; б) проверяется каждый reference в SignedInfo на предмет соответствия DigestValue, если неверен выдается ошибка; в) если reference имеет особый тип (как signed properties) в рамках б) после сверки digestValue в Reference проводится проверка и самого текста SignedProperties. То есть если в) дает ошибку, это же считается ошибкой этапа б). Если техподдержка не разбиралась в деталях первый раз, то могут наговорить много ерунды.
Подробнее по в): по значениям Issuer и номеру сертификата выбирается сертификат (то есть перебирается каждый сертификат и декодируется из base64, берутся его свойства) из KeyInfo (этой проверке все равно что он там один!) и если сертифтикат не выбрался, то либо будет исключение либо получится совсем другое значение от пустой строки. Если сертификат выбрался, то действительно считается хэш от декодированного из base64 сертификата как массива байтов (сертификат к канонической форме не приводится). В итоге изначальная ошибка по б) может получиться по следующим причинам:
1. ID на который указывает URI из reference б) не уникален в документе и выбрался неправильный тег вместо signedProperties;
2. в документе нет тега с ID на который указывает URI из reference б).
3. изменение текста signedProperties и его потомков после вычисления хэша от канонической формы signedProperties (тут надо понимать что если каноническая форма signedProperties неэксклюзивная, то на нее повлияют и изменения пространств вышестоящих тегов, не только самого signedProperties и его потомков);
4. неверное вычисление канонической формы signedProperties (эксклюзивную можно проверить той программкой), тут же болтается параметр PreserveWhitespace, который не отражается в xml и надо подбирать при проверке если в xml присутствуют переводы строки и отступы перед тегами;
5. вычисление не той канонической формы signedProperties, что указана в reference б);
6. неверное вычисление хэша от канонической формы signedProperties (как правило маловероятно, но могут быть разные представления одного и того же значения хэша: little endian и big endian);
7. фактический алгоритм хэша от канонической формы signedProperties отличается от указанного в б);
8. неверные значения Issuer или номера сертификата;
9. неверное значение хэша сертификата (аналогично - little endian и big endian);
10. фактический алгоритм хэша сертификата отличается от указанного в signedProperties;
Пункты 1-7 аналогичны для а).
Автор: oleg_kashin Как проверить правильность формирования DigestValue в reference?
Я правильно понимаю что 1 reference ... формируется для подписываемого тэга hous:exportHouseRequest
Правильно, более точно будет сказато что для тега в котором ID соотносится с URI в reference (в цитате из первого референса URI "#a03356a7e8bd4239ad69b3e9c949bca1", значит для тега с ID "a03356a7e8bd4239ad69b3e9c949bca1"). Это должен быть "подписываемый тег".
Автор: oleg_kashin Второй для объекта <ds:Object>
Цитата:<ds:Reference URI="#xmldsig-f865747a-c889-44ff-9d7e-6d58bf5c7979-signedprops" Type="http://uri.etsi.org/01903#SignedProperties">
Он же по коду добавляется при добавлении объекта <ds:Object> он же XadesObject.
Т.е. перед расчетом хэша по указанному алгоритму проводится приведение в соответствии с тем, что задано в ds:Transforms ? Далее результат записывается в ds:DigestValue
В целом да, сначала трансформы потом вычисление хэша. Обратите внимение, что URI указывает на signedProperties, а не на ds:Object. Более точно сказать, что ds:Object просто обертка, а XadesObject это тег xades:QualifyingProperties и его потомки, так как более продвинутые версии формата Xades включают еще и неподписанные свойства (неподписанные в том смысле, что у них "не наша" подпись и для них не создается reference).
Автор: oleg_kashin Вот что то не понимаю как посмотреть что идет на расчет DigestValue в исходном коде
https://github.com/Good-...ibrary/XadesSignedXml.cs строка 1463-1475 вызывается System.Security.Cryptography.Xml.Reference.UpdateHashValue с аргументами m_containingDocument - xmlDocument изначальный,refList - System.Security.Cryptography.Xml.CanonicalXmlNodeList
refList заполняется 1456 - добавляется xml Object после добавления префикса ds. Не понимаю для чего нужен refList и почему ниже не 1483 не делается CanonicalXmlNodeList_Add для reference
Может кто скинет что посмотреть по этому направлению ?- хотя получается судя по ответу ГИС ЖКХ я ошибку ищу не там))
В C# мне немного неудобно разбираться. Как я понимаю, в итоге все идет в базовый объект от Майкрософт, который и вычисляет значения, поэтому нужно включить лог в нем.
https://www.cryptopro.ru...&m=105590#post105590Вообще при подписании последовательность такая - 1) формируем первый референс, применяем трансформы к подписываемому тегу, считаем хэш от результата трансформов, кодируем в base64 и заполняем в референс;
2) формируем второй референс, смотрим что это xades, считаем хэш от сертификата, берем реквизиты сертификата, заполняем SignedProperties;
3) применяем трансформы к signedProperties, считаем хэш от результата трансформов, кодируем в base64 и заполняем в референс;
4) когда все референсы готовы, применяем трансформы к SignedInfo, результат трансформа подписываем (то есть тоже вычисляется хэш, хэш подписывается закрытым ключом, соответствующим сертификату), результат подписи кодируем в base64 и заполняем в SignatureValue;
5) добавляем сертификат в KeyInfo (можно добавить всю цепочку, а не только один сертификат).
Автор: oleg_kashin Правильно ли понимаю по каноникализации?
Изначально xml должна быть вся приведена к "http://www.w3.org/2001/10/xml-exc-c14n#" или только при расчете.
Обязательно - при расчете, изначальный вид задается требованиями ИС, он может или быть каноническим или не быть. Некоторые ИС требуют расположения атрибутов в определенном порядке (отличном от канонического), если не ошибаюсь ГИС ЖКХ как раз из таких и отправить канонический вид изначально не выйдет - после проверки подписи ГИС начнет ругаться на порядок атрибутов. Если бы такого не было - надежнее отправлять сразу каноническую форму с PreserveWhitespace = false, при этом будут выкинуты спорные символы.
Автор: oleg_kashin В принципе нормально, так как изначально форма требуемая ГИС ЖКХ, а не каноническая. В приложение можно вставлять только вычисляемый фрагмент (дополненный объявлениями пространств имен из вышестоящих тегов, на которые ругнется).
Автор: oleg_kashin Главный вопрос как проверить правильность DigestValue в reference конечно..
Цитата:Какая фактически выполняется каноникализация - эксклюзивная или неэксклюзивная
Эксклюзивная.
Если можно путь в исходнике и номер строки где это нашли.
Автор: oleg_kashin Еще раз пример запроса подписанный во вложении
Например, мне будет гораздо проще проверить если не будет отступа пробелами и перевода строки перед каждым тегом внутри exportNsiListRequest, так как это тоже влияет на каноническую форму (сравните разные PreserveWhilespace в программке).