Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline evarlamov  
#1 Оставлено : 9 августа 2021 г. 8:38:44(UTC)
evarlamov

Статус: Участник

Группы: Участники
Зарегистрирован: 06.11.2015(UTC)
Сообщений: 13
Российская Федерация

Сказал(а) «Спасибо»: 2 раз
Помогите справиться, что-то застрял.
При взаимодействии с тестовым контуром ФСС получаю ошибку:
Ошибка при проверки ЭЦП. Алгоритм ключа не соответствует алгоритму подписи

Инструменты: delphi, JwaWinCrypt

Формирую xml-запрос (PrParseFilelnlpu) и пытаюсь подписать его двумя подписями.
Первой подписываю элемент body. Для этого:
0) обращаюсь к контексту нужного криптопровайдера
1) канонизирую элемент,
2) создаю хэш CryptCreateHash(ACryptoProvider, CALG_GR3411_2012_256, 0, 0, hash)
3) добавляю данные из шага 1) в хеш
4) вычисляю данные по полученному хэшу (CryptHashData(hash, PByte(aByte), Length(aByte), 0))
5) конвертировав результат в строку, помещаю все в digestValue
6) повторяю шаги 1)-5) уже ля элемента SignedInfo и помещаю конвертированный в строку результат в SignatureValue

Второй пописью подписываю каждый элемент row в теле документа. Для этого делаю те же шаги, но обращаюсь к другому контейнеру.
Подпись (digestValue, SignatureValue) будет размещена в новой секции Security

- как выбираю нужный контейнер:
вызываю CryptAcquireContext(AProvider, <Имя нужного контейнера>, nil, 80, 0))
и использую AProvider

Подписанный файл не проходит проверку и здесь https://www.justsign.me/verifyqca/Verify/ - XML подпись не верна.
В чем может быть причина?
Приложу этот самый подписанный документ SOAPRequestSign.xml (15kb) загружен 6 раз(а).
Offline two_oceans  
#2 Оставлено : 11 августа 2021 г. 12:32:05(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,351
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 90 раз
Поблагодарили: 319 раз в 300 постах
Добрый день.
Дельфи в разделе .NET и даже не специфичный для ЭЛН вопрос по подписанию XML - просто чудом увидел. Ближе к теме:
1) похоже неправильно описали отличия на шаге 5: для SignedInfo - еще вызывается CryptSignHash именно его результат идет на переворот/отзеркаливание порядка байтов, потом конвертируется в base64 и сохраняется в SignatureValue, уничтожается вызовом CryptDestroyHash.

для подписываемого фрагмента - результат получается через GetHashParam(_,HP_HASHVAL,_), потом конвертируется в base64 и сохраняется в DigestValue, уничтожается вызовом CryptDestroyHash.

Примечание. В случае, когда хэш создается не для CryptSignHash, можно создать контекст криптопровайдера так: CryptAcquireContext(AProvider, nil, nil, 80, CRYPT_VERIFYCONTEXT) - исключает обращение к контейнеру, когда он реально не нужен. В данном случае, хэш от подписываемого фрагмента (DigestValue) не идет в CryptSignHash, то есть контейнер можно не тревожить. Аналогично при проверке DigestValue и SignatureValue.

Про переворот. В стандарте регламентирован порядок байт "старший байт по младшему адресу", а КриптоПро CSP через функции GetHashParam(_,HP_HASHVAL,_) CryptSignHash возвращает в "младший байт по младшему адресу" (как принято для процессоров x86). С гост-2012 переворачивать хэш "внезапно" стало не нужно, но для значения подписи необходимость остается. Через другие средства (как .Net) необходимости может не быть - результат автоматически переворачивает прослойка между криптопровайдером и высокоуровневым интерфейсом.

Смотрим что у Вас на практике: по длине SignatureValue (в 2 раза длиннее, чем DigestValue) видно, что CryptSignHash вызывали - тут все правильно. Остается момент с "отзеркаливанием" порядка байтов.
Переворот у меня реализован упрощенно так (через 2 буфера, для отладки "до" и "после"):

2) если теги вложенные, то рекомендуется сначала подписывать самый "глубокий" - возможно случайное изменение xml кода в процессе подписания, особенно когда формируете xml вручную. Следовательно сначала подписываете Row, потом Body

3) Обратите внимание, что ds:CanonicalizationMethod Algorithm это алгоритм применяемый к SignedInfo, а ds:Transform Algorithm это алгоритм применяемый к подписываемому фрагменту. Как-то Вы замечательно каноникализируете все подряд, хотя в трансформах у подписи тега Row пусто, каноникализации нет. При проверке будут точно применены явно указанные трансформы, а вот отступления конкретной ИС от стандарта (когда трансформа никакого нет, а ИС все равно каноникализирует и считает верным) не пройдут проверку на общедоступном средстве проверки. Поэтому если каноникализируете и проверяете себя на сайте - добавьте трансформ, так Вы сообщите средству проверке о том, что делаете при подписании.

4) ds:Reference URI="#ELN_1207700165023" ведет в никуда - нет такого Id в документе, зато есть soapenv:Body wsu:Id="OGRN_1207700165023". Понимаю, запутались уже. Однако ряд средств проверки подписи выбирает пустую строку когда не находят Id (хэш уже будет совсем другой и выдаст ошибку), остальные сразу вываливаются в ошибку (не нашли фрагмент).

UPD: Результаты проверки в моей программе: подпись Row выдала ошибку SignatureValue (удаление табуляций и переводов строк не помогло). DigestValue тоже выдало ошибку обработки.
Вторая подпись прошла проверку SignatureValue после удаления табуляций и переводов строк. ds:Reference URI не нашелся. Так что да, подписи не верны.

Отредактировано пользователем 11 августа 2021 г. 13:12:38(UTC)  | Причина: Не указана

thanks 2 пользователей поблагодарили two_oceans за этот пост.
Андрей * оставлено 11.08.2021(UTC), evarlamov оставлено 12.08.2021(UTC)
Offline evarlamov  
#3 Оставлено : 12 августа 2021 г. 12:01:24(UTC)
evarlamov

Статус: Участник

Группы: Участники
Зарегистрирован: 06.11.2015(UTC)
Сообщений: 13
Российская Федерация

Сказал(а) «Спасибо»: 2 раз
Добрый день.
Спасибо, помогло. Путаницу со ссылками Reference URI сам обнаружил, а вот за объяснение того, что не нужно канонализировать подписываемый элемент - еще раз спасибо.
Добился корректных подписей от сервиса https://www.justsign.me/verifyqca/Verify/

Но поменял подписываемые блоки, опять что-то сломалось. Одна из подписей стала некорректна.

Не подскажете, в чем может быть дело?
В приложенном примере подписью 1 подписан элемент treatPeriod, а подписью 2 - элемент row
SOAPRequestSign.xml (13kb) загружен 3 раз(а).
Offline two_oceans  
#4 Оставлено : 13 августа 2021 г. 5:45:14(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,351
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 90 раз
Поблагодарили: 319 раз в 300 постах
Результат проверки в моей программке:
1) подпись treatPeriod: SignatureValue верно, DigestValue верно = подпись верна
2) подпись row: SignatureValue верно, DigestValue отличается = подпись неверна
Код:
=== WARNING: digest differ:
[DgbbIIMj414dCRT09Ga8APCVWFFiGELqlouAaIT1OI4=] fact // вычислено фактически
[fFJW3cFMxSVUITu0SVJhq574r7gpuN9haMvXXJd0QXs=] expected // ожидалось, указано в Reference
В данном случае трансформ каноникализации указан в Reference, так что каконикализация применена при проверке. Текст, полученный для вычисления хэша (но могу и ошибаться в плане представления некоторых символов и порядка пространств имен, так как может быть у меня включено отступление от стандарта для СМЭВ):
Код:
<row xmlns="http://www.fss.ru/integration/types/eln/mo/v01" xmlns:NS2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" NS2:Id="ELN_900000585992"><unconditional>false</unconditional><snils>16585732610</snils><surname>Иванов</surname><name>Иван</name><patronymic>Иванович</patronymic><lnCode>900000585992</lnCode><primaryFlag>true</primaryFlag><duplicateFlag>false</duplicateFlag><lnDate>2021-08-11</lnDate><lpuName>ГБУЗ ЦРБ №1</lpuName><lpuAddress>Г.НИЖНИЙ НОВГОРОД, УЛ. ГОРЬКОГО 117</lpuAddress><lpuOgrn>1207700165023</lpuOgrn><birthday>2000-08-24</birthday><gender>1</gender><reason1>05</reason1><diagnos>0000000000</diagnos><date1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"></date1><date2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"></date2><mseDt1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"></mseDt1><mseDt2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"></mseDt2><mseDt3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"></mseDt3><mseInvalidGroup>0</mseInvalidGroup><treatPeriods><treatFullPeriod><treatPeriod xmlns="http://www.fss.ru/integration/types/eln/v01" NS2:Id="ELN_900000585992_1_doc"><treatDt1>2021-08-12</treatDt1><treatDt2>2021-08-18</treatDt2><treatDoctorRole>ПЕДИАТР</treatDoctorRole><treatDoctor>ГАБЕЕВА ИЧ</treatDoctor></treatPeriod></treatFullPeriod></treatPeriods><lnState>020</lnState><writtenAgreementFlag>true</writtenAgreementFlag></row>
На всякий случай перепроверил, что данный текст сохраненный в файл в кодировке UTF8 без ByteOrderMark (длина 1585) дает вычисленный хэш.
Код:
0E06DB208323E35E1D0914F4F466BC00F0955851621842EA968B806884F5388E
DgbbIIMj414dCRT09Ga8APCVWFFiGELqlouAaIT1OI4=
FLIP RESULT:
8E38F58468808B96EA421862515895F000BC66F4F414091D5EE3238320DB060E
jjj1hGiAi5bqQhhiUViV8AC8ZvT0FAkdXuMjgyDbBg4=


Для гибкости, когда трансформ нужен, а когда нет, у меня при подписании сначала добавляются предполагаемые трансформы в референс. При подписании такая обработка референса:
1) содержимое референса (URI, Id, Type, список трансформов, алгоритм хэша) блокируется;
2) выполняется процедура как при проверке референса: выбирается фрагмент по URI, для каждого трансформа в референсе по общему списку алгоритмов ищется нужный и применяется к фрагменту, вычисляется хэш согласно алгоритму из референса (аналогично по общему списку алгоритмов ищется нужный алгоритм хэша и применяется);
3) вычисленное значение хэша заносится в референс.
Потом все референсы составляются в SignedInfo, который блокируется и к нему применяется CanonicalizationMethod, потом SignatureMethod, заносится SignatureValue.

При проверке референса:
1) считывается список трансформов, URI, Id, Type, алгоритм хэша и значение хэша.
2) выбирается фрагмент по URI, для каждого трансформа в референсе по общему списку алгоритмов ищется нужный и применяется к фрагменту, вычисляется хэш согласно алгоритму из референса (аналогично по общему списку алгоритмов ищется нужный алгоритм хэша и применяется);
3) вычисленное значение хэша сравнивается со считанным значением.

Отредактировано пользователем 13 августа 2021 г. 7:12:02(UTC)  | Причина: Не указана

Offline evarlamov  
#5 Оставлено : 16 августа 2021 г. 11:03:03(UTC)
evarlamov

Статус: Участник

Группы: Участники
Зарегистрирован: 06.11.2015(UTC)
Сообщений: 13
Российская Федерация

Сказал(а) «Спасибо»: 2 раз
Спасибо.
Постараюсь повторить вашу схему.
Обнаружил, что если в документе встречается строка типа <date1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
то подпись становится некорректной. (даже если этот namespace прописать где-то в родительских элементах)
Это как-то можно объяснить? Т.е. есть два документа, подписываемые по одной схеме, отличаются лишь на одну строку. Но один проходит проверку, второй - нет
SOAPRequestSign0.xml (13kb) загружен 5 раз(а).
SOAPRequestSign1.xml (13kb) загружен 4 раз(а).
Offline Рафик  
#6 Оставлено : 17 октября 2021 г. 2:16:44(UTC)
Рафик

Статус: Новичок

Группы: Участники
Зарегистрирован: 14.11.2018(UTC)
Сообщений: 6
Российская Федерация
Откуда: Старая Русса

Сказал(а) «Спасибо»: 2 раз
Может кто подскажет, делаю метод prParseFilelnlpuRequest
Подписываю файл все согласно алгоритмов
почему то выдает подпись не действительная при чем обе, уже не знаю где искать проблему

прикладываю файлик

Подпись 1
Результат проверки
Подпись не действительна






SOAPRequestSign.xml (13kb) загружен 1 раз(а).
Offline Рафик  
#7 Оставлено : 17 октября 2021 г. 20:10:36(UTC)
Рафик

Статус: Новичок

Группы: Участники
Зарегистрирован: 14.11.2018(UTC)
Сообщений: 6
Российская Федерация
Откуда: Старая Русса

Сказал(а) «Спасибо»: 2 раз
Автор: Рафик Перейти к цитате
Может кто подскажет, делаю метод prParseFilelnlpuRequest
Подписываю файл все согласно алгоритмов
почему то выдает подпись не действительная при чем обе, уже не знаю где искать проблему

прикладываю файлик

Подпись 1
Результат проверки
Подпись не действительна






SOAPRequestSign.xml (13kb) загружен 1 раз(а).


Разобрался, неправильно канонизировал файл
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.