Skip to content

SignService 1.3.0: соподписание по содержимому документа и полная проверка ГОСТ-подписей КриптоПро - #5

Merged
zaynullinmi merged 3 commits into
mainfrom
claude/ecp-document-signing-service-dbbut0
Oct 9, 2026
Merged

zaynullinmi merged 3 commits into
mainfrom
claude/ecp-document-signing-service-dbbut0

Conversation

@zaynullinmi

Copy link
Copy Markdown
Owner

Зачем

  1. Ошибка в 1.2.0. КриптоПро и CryptoAPI (включая саму SignService на Windows) записывают в signatureAlgorithm OID ГОСТ-ключа с параметрами, а BouncyCastle такие подписи отклоняет. Поэтому реальные ГОСТ-подписи получали «не определено» и при объединении помечались как непроверенные.
  2. Соподписание. Ветка форка sozertsatel/SignService (cursor/cosign-discovery-gost-cb6f) добавляет поиск подписей по содержимому документа. Идея нужная, но в исходном виде в ветке были проблемы, найденные при ревью:
    • обход проверки: подпись без messageDigest принималась для любого документа;
    • зависание интерфейса при добавлении файлов;
    • перезапись подписей оригинала в режиме «подписывать копию со штампом»;
    • жёсткие пути в тестах.
  3. Ревью форка debug23win (PR Исправить обработку подписей и МЧД; добавить разделение и удаление подписанта #2). Присланные сценарии проверены на текущем коде и закреплены тестами.

Что сделано

Проверка ГОСТ

  • На проверку идёт копия подписи без параметров в signatureAlgorithm, OID ключа заменён на OID алгоритма подписи. Это поле не входит в подписанные данные. Все проверки BouncyCastle (messageDigest, content-type, значение подписи) сохраняются, исходные байты подписантов при объединении не меняются.
  • При подписанных атрибутах без messageDigest документ считается несоответствующим.
  • Покрыты ГОСТ 2001, 2012-256 и 2012-512 в трёх вариантах: OID подписи с параметрами, OID ключа с параметрами (как CryptoAPI), OID ключа без параметров. Повреждённые подписи, другой документ и подписи без messageDigest отклоняются.

Соподписание по содержимому (по ветке форка, с доработками)

  • Подписанты сопоставляются той же криптопроверкой, что и при объединении, поэтому прогноз исключений совпадает с результатом.
  • «документ.sig» предлагается всегда, поэтому голый PKCS#7 и подписи с неизвестным хешем не теряются.
  • Поиск идёт в фоне, документ читается и хешируется один раз. 10 документов по 10 МБ плюс подписи: было 7,6 с в потоке интерфейса, стало 17 мс. Подписание ждёт окончания поиска.
  • Перетащенные подписи становятся приложенными: результат пишется рядом с документом, чужие файлы не перезаписываются.
  • Резервная копия создаётся только при замене файла без объединения или при исключении подписантов.
  • Выбор режима блокируется на время подписания. После подписания варианты обновляются для следующего соподписания.
  • «Подписывать копию со штампом» не трогает подписи оригинала. В форке групповая подпись оригинала здесь перезаписывалась.
  • Из форка также перенесены подтверждения, строка плана, итог «9 (8 + ваша)» и имя результата «Объединить .sig».
  • Workflow test-latest и путь /opt/cursor в тестах не перенесены.

Тесты по ревью форка debug23win

  • Изменённое значение подписи при верном messageDigest исключается: в «Объединить .sig», в «Собрать контейнер» и при соподписании.
  • Сертификат, который был только в контейнере исключённого подписанта, сохраняется.
  • МЧД без номера или даты выдачи, а также с просроченным или недоверенным самоподписанным сертификатом руководителя не проходит как «Ok».

Проверка

  • dotnet build: 0 предупреждений.
  • dotnet run --project tests/SignService.Tests -c Release — ALL TESTS PASSED, включая хранилище сертификатов и смоук интерфейса (строка соподписания).
  • Мутационные проверки: регрессионный тест падает, если вернуть старое поведение. Проверено для режима копии со штампом.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624


Generated by Claude Code

claude added 3 commits October 9, 2026 10:53
… КриптоПро

Перенесено из ветки cursor/cosign-discovery-gost-cb6f форка
sozertsatel/SignService и доработано.

Соподписание:
- подписи документа ищутся в его папке по содержимому, а не по имени
  («договор-.pdf .sig» для «договор.pdf»); у файла — выбор «Добавить к
  найденной подписи» или «Создать новую», строка плана («будет добавлена
  подпись №9 к …»), подтверждение перед заменой файла и исключением
  подписантов, итог «Подписан: 9 (8 + ваша)»;
- в отличие от форка: подписанты сопоставляются той же криптопроверкой,
  что и при объединении; «документ.sig» предлагается всегда (голый
  PKCS#7 и подписи с неизвестным хешем не теряются); поиск идёт в фоне,
  документ читается и хешируется один раз (добавление 10 документов по
  10 МБ с подписями: было 7,6 с в потоке интерфейса, стало 17 мс);
  перетащенные подписи — приложенные, результат пишется рядом
  с документом, чужие файлы не перезаписываются; выбор блокируется на
  время подписания; после подписания варианты обновляются для следующего
  соподписания; резервная копия — только при замене без объединения
  или исключении подписантов;
- режим «подписывать копию со штампом» не трогает найденные подписи
  оригинала (в форке групповая подпись оригинала перезаписывалась,
  а её подписанты исключались);
- «Объединить .sig» называет результат «документ.sig» и не затирает
  существующий файл.

Проверка ГОСТ:
- КриптоПро и CryptoAPI (в том числе SignService на Windows) пишут
  в signatureAlgorithm OID ключа с параметрами, BouncyCastle такие
  подписи отклонял — в 1.2.0 они получали «не определено». Теперь
  проверяется копия без этих параметров с полными проверками
  BouncyCastle; обходной путь форка, принимавший подпись без
  messageDigest для любого документа, не перенесён;
- подпись с подписанными атрибутами без messageDigest не соответствует
  документу (раньше проверка документа показывала «соответствует»).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
В коде PR #2 объединение сверяло только messageDigest, МЧД проверялась
без доверия и отзыва, а сертификат оставшегося подписанта терялся
вместе с исключённым входом. Тесты закрепляют, что в текущей версии:
- изменённое значение подписи при верном messageDigest исключается
  в «Объединить .sig», «Собрать контейнер» и при соподписании;
- сертификат, который был только в контейнере исключённого подписанта,
  сохраняется, и оставшаяся подпись проходит проверку;
- МЧД без номера или даты выдачи, с просроченным или недоверенным
  самоподписанным сертификатом руководителя не проходит как «Ok».

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
@zaynullinmi
zaynullinmi merged commit 5177fd1 into main Oct 9, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants