Автор: Infopol Привел SignedData к нужному виду
Далее в программе
Цитата:CADESCOM_CONTENT_ENCODING_TYPE=0 //DBASE64
HashData.Algorithm= CADESCOM_HASH_ALGORITHM(CADESCOM_HASH_METOD) //101
HashData.DataEncoding= CADESCOM_CONTENT_ENCODING_TYPE
hashSignInfo=( CadesComHash(SignInfo,CADESCOM_HASH_METOD))
HashData.Hash(EnCode64Str(SignInfo))
...
ОТЛАДКА(HashData.Value,EnCode64Str(HashData.Value))
Xml.sol(239/1310:9) 6E166A15ACAC3E6FDD22DDA97CD028BE8F5EF3F1B16E406DD5B85E63927C5210, NkUxNjZBMTVBQ0FDM0U2RkREMjJEREE5N0NEMDI4QkU4RjVFRjNGMUIxNkU0MDZERDVCODVFNjM5MjdDNTIxMA==
ОТЛАДКА( ДЛИНА(rawstr),rawstr ) // Длина 128
Xml.sol(240/1311:10) 128, 7119BFFAE59969E6C86C42052...
Сделал все как вы рекомендовали...верификация файла - НЕТ
Выглядит уже лучше. Коллега, в коде похоже не учтена особенность возвращаемого значения из HashData.Value и RAW.SignHash, которая должна быть описана в справке - данные хэша и "чистой" подписи возвращаются в шестнадцатиричном виде, их надо декодировать перед дальнейшими преобразованиями (переворачиванием или кодированием в BASE64). Для хэша нужно декодировать когда формируете Reference. Это прекрасно видно на отладке - в шестнадцатиричный вид при отладке не переводили, а выдана строка в шестнадцатиричном виде. Из-за этого длина будет в 2 раза больше и значение совсем не то, что ожидает функция проверки. Определить это функция проверки хэша не сможет, так как теоретически шестнадцатиричный вид допустимое значение, просто длина больше. Следовательно функция проверки хэша просто выдаст отказ без дополнительной диагностики.
Входная кодировка похоже указана неверно, при кодировании BASE64 указывается 1, а в коде 0:
https://docs.cryptopro.r...om_content_encoding_typeCADESCOM_BASE64_TO_BINARY Кодировка BASE64. 0x01
CADESCOM_STRING_TO_UCS2LE Кодировка UTF-8 или UNICODE. 0x00
Алгоритм под вопросом - 101 закомментировано.
CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256 Алгоритм ГОСТ Р 34.11-2012. 101
В SignedInfo опять где-то потерялись пары слешей и всплыли переводы строк. Длина 582 байта.
Если вернуть слеши, убрать переводы строк, то:
Код:<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102012-gostr34112012-256"></ds:SignatureMethod><ds:Reference URI="#body"><ds:DigestMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256"></ds:DigestMethod><ds:DigestValue>MjE1QjEzRjc1QzJGQUE2QzFDNzk0NzdGNUMxQ0E5NDIxOTdDRURFMTRGNTIxOTc4QUQwQUFEQjIxNEVEMkEyNA==</ds:DigestValue></ds:Reference></ds:SignedInfo>
7A19D271187FDF572E0906EE2325A923C17462D587701FF41DB09D327C2E8A31
ehnScRh/31cuCQbuIyWpI8F0YtWHcB/0HbCdMnwuijE=
FLIP RESULT:
318A2E7C329DB01DF41F7087D56274C123A92523EE06092E57DF7F1871D2197A
MYoufDKdsB30H3CH1WJ0wSOpJSPuBgkuV99/GHHSGXo=
Подручными средствами можно вычислить хэш командой (имя_файла укажите свое)
Код:"C:\Program Files (x86)\Crypto Pro\CSP\cpverify.exe" -mk -alg GR3411_2012_256 имя_файла -inverted_halfbytes 0
Цитата:SignatureSection=CreateSignatureSection(hash,УБР_ПРОБ( rawstr),X509Cert,ДА)
SignatureSection=XML_SirCanocalizireString(SignatureSection)
Text= InsertSignature(Text,SignatureSection,"")
Замечание. Если внешние библиотеки вдруг используют каноникализацию .Net, то версия .Net имеет значение - верная работа будет примерно с версии 4.5 включительно до версии 4.7.2 включительно. На меньших версиях работает неверно для некоторых документов, на более новых версиях неизвестно как работает.
Что происходит в этом месте кода мне не совсем понятно. Зачем еще что-то создается и тем более каноникализируется - в том смысле, что не вижу чтобы туда передавалась переменная SignInfo, которую подписали и которая уже должна быть в каноничном виде. Без передачи той самой SignInfo нет никакой гарантии прохождения проверки подписи.
В том смысле, что если следовать совсем уж точно алгоритму из стандарта, то сначала создается каркас ds:Signature
в самом документе (ds:SignedInfo (ds:CanonicalizationMethod, ds:SignatureMethod), пустой тег ds:SignatureValue, пустой ds:KeyInfo), потом они заполняются значениями (ds:SignatureMethod должен согласовываться с сертификатом), добавляются один или несколько ds:Reference. К ds:Reference указываются атрибут URI (по необходимости Type и ID), добавляется ds:Transforms, все действия с фрагментом отражаются трансформами, добавляется ds:DigestMethod, считается хэш по ds:DigestMethod в ds:DigestValue. После добавления и заполнения всех ds:Reference запрещается изменение ds:SignedInfo в документе, но делается копия для каноничного вида ds:SignedInfo. Все изменения (исключения переносов строк и тд) ds:SignedInfo в документе нужно делать до момента взятия копии.
Отмечу, что парсером xml в копию фрагмента переносятся объявления пространств имен (xmlns) из вышестоящих тегов и наследуемые атрибуты с префиксом xml, фактически из них для ds:SignedInfo обязателен только xmlns:ds из ds:Signature, то есть по логике ds:Signature уже должен быть. Остальные xmlns не используются в ds:SignedInfo и каноникализация их удалит. Небольшие отклонения от алгоритма допустимы, но с ними нужно действовать очень аккуратно. Малейшее изменение текста и хэш уже не сойдется. Так, если совпадают префиксы ds:SignedInfo и ds:Signature, то в ds:SignedInfo необязательно указывать объявление xmlns:ds в документе (но указать не запрещено). Однако в каноничной копии объявление ds:SignedInfo обязательно должно быть. Если префиксы не совпадают, то объявление обязательно и в документе и в копии.
Еще момент в том, что парсер xml при открытии документа "нормализует" документ - переводы строк #13#10 заменяются на символ #10, потом одиночные символы #13 заменяются на символ #10. Формально это должно быть сделано до каноникализации, то есть символ #13 вообще не должен дойти до каноникализации и до вычисления хэша. Нет переводов строк - нет проблемы.
Сохранение табуляций и пробелов между тегами (отступов) также проблемный вопрос - у парсера xml есть параметр PreserveWhitespace вот только он никак не отражается в самом документе и можно только гадать какое значение параметра у проверяющей стороны. Нет отступов - нет проблемы.
По счастью, в примере нет кириллицы. Если потом будет, то надо помнить, что на каноникализацию должен идти документ в кодировке UTF-8.
Далее делается каноникализация копии SignedInfo, вычисляется хэш от каноничной копии SignedInfo (алгоритм хэша из ds:SignatureMethod), хэш подписывается в RAW подпись, полученное значение вставляется в SignatureValue.
В примере XML оторван посередине ds:SignedInfo, нет всего промежуточного между тегами SignatureValue и X509Certificate. Для полной проверки желательно прикрепить весь файл без сокращений. Без сертификата не получится проверить SignatureValue. Если не хотите светить рабочий сертификат на форуме, но подойдет и тестовый.
Отредактировано пользователем 13 апреля 2022 г. 8:09:50(UTC)
| Причина: Не указана