Как подпись устроена внутри PDF
ISO 32000-2 §12.8 Spec: ETSI EN 319 142-1 ETSI EN 319 142-1 Spec: RFC 5652 RFC 5652 Evidence: Standard-backed
Подпись PDF не оборачивает файл снаружи. Она встроена внутрь него: словарь, который именует подпись, и дайджест, вычисленный по объявленному диапазону байтов, намеренно пропускающему само значение подписи. На этой странице объясняется этот механизм и, что не менее важно, чего он не гарантирует.
Почему это важно
Заголовок раздела «Почему это важно»“Документ подписан” — фраза, на основе которой люди принимают решения. Они связывают её с платежом, одобрением, юридическим обязательством. Если вы не знаете точно, какие байты охватывает подпись, вы не можете сказать, что на самом деле доказывает действительный результат. PDF может содержать полностью действительную подпись и при этом показывать читателю содержимое, которого подписавший никогда не видел, потому что оно было добавлено после подписания, в области, о которой подпись ничего не заявляла. Понимание того, где начинаются и заканчиваются полномочия подписи, — это разница между обоснованным решением и решением, основанным на надежде.
Если коротко
Заголовок раздела «Если коротко»- Подпись PDF находится в словаре подписи и поле подписи внутри документа, а не в виде внешней оболочки.
- Подписанные байты объявляются массивом
ByteRange: два сегмента(offset, length), которые вместе охватывают весь файл, кроме шестнадцатеричного значения подписи, хранящегося в записиContents. - Криптографическая подпись защищает именно дайджест этих двух соединённых сегментов.
- Всё, что добавлено позже в новой редакции, находится вне исходного диапазона байтов. Исходная подпись остаётся действительной; она ничего не заявляла о новых байтах.
- Подпись для одобрения и подпись для сертификации различаются по охвату: сертификация (DocMDP) ограничивает, какие дальнейшие изменения допустимы; одобрение — нет.
Как это реализовано в NextPDF
Заголовок раздела «Как это реализовано в NextPDF»NextPDF строит подпись по модели формата, в строгом порядке, поэтому диапазон байтов получается точным, а не приблизительным.
Когда движок записывает подпись, он сначала резервирует слот фиксированного размера для
значения Contents и записывает заполнитель ByteRange фиксированной ширины. Он
дожидается, пока весь документ будет записан, включая таблицу
перекрёстных ссылок и маркер конца файла. Только после этого движок вычисляет два настоящих смещения,
записывает их обратно в заполнитель, не сдвигая ни одного байта, хеширует два
сегмента и помещает полученный объект CMS в зарезервированный слот. Заполнитель
дополняется нулями до постоянной длины именно для того, чтобы подстановка
настоящих чисел не сдвинула хешируемые байты. Это единственный порядок, который
даёт самосогласованную подпись. Любой сбой в этой
последовательности движок рассматривает как жёсткую ошибку, а не как тихий откат.
В профиле PDF 2.0 сам объект подписи представляет собой откреплённую структуру CMS
SignedData. Словарь PDF говорит где и как; объект CMS
несёт кто и криптографическое доказательство.
- Step 1 of 4: ISO 32000-2 §12.8.1 — ByteRange digest & signature dictionary
- Step 2 of 4: ISO 32000-2 §12.8.3.3 — ETSI.CAdES.detached SubFilter
- Step 3 of 4: ETSI EN 319 142-1 PAdES baseline profile
- Step 4 of 4: RFC 5652 CMS SignedData in Contents
Что говорят стандарты
Заголовок раздела «Что говорят стандарты» Evidence: Standard-backed Механизм определяется в
Spec: ISO 32000-2, §12.8.1 ISO 32000-2 §12.8.1 . Дайджест диапазона байтов
вычисляется по диапазону байтов, указанному в записи ByteRange. Этот диапазон
должен охватывать весь файл, включая словарь подписи, но исключая
значение подписи — запись Contents. ByteRange — это массив
пар целых чисел — начальное смещение и длина. Разрывные диапазоны
используются именно для того, чтобы дайджест мог опустить само значение подписи.
Для профиля PDF 2.0 Spec: ISO 32000-2, §12.8.3.3 ISO 32000-2 §12.8.3.3 указывает, что когда SubFilter равен ETSI.CAdES.detached, значение Contents представляет собой объект CMS SignedData в кодировке DER — ту же структуру, которую
Spec: RFC 5652 RFC 5652 определяет, — а профиль PAdES этого объекта
описан в Spec: ETSI EN 319 142-1 ETSI EN 319 142-1 .
Охват у подписей бывает разным. Spec: ISO 32000-2, §12.7.4.5 ISO 32000-2 §12.7.4.5 определяет разрешение MDP: значение 0 делает подпись подписью одобрения, тогда как значения 1–3 делают её подписью сертификации, которая ограничивает, какие из дальнейших изменений сохраняют соответствие документа. Механизм диапазона байтов тот же; обещание относительно будущего — другое.
Движок NextPDF реализует именно это: заполнитель ByteRange фиксированной ширины, дайджест двух соединённых сегментов и откреплённый объект CMS в зарезервированном слоте Contents, который финализируется только после того, как файл полностью готов.
Практический пример
Заголовок раздела «Практический пример»Вы редко собираете ByteRange вручную. Смысл примера — показать форму результата, чтобы вы могли узнать её при осмотре подписанного файла.
<?php
declare(strict_types=1);
use NextPDF\Security\Signature\ByteRangeCalculator;
// Offsets the engine knows only after the whole PDF is written:// $contentsStart — byte just before the '<' of the hex signature// $contentsEnd — byte just after the '>' that closes it// $fileLength — total file size in bytes$range = ByteRangeCalculator::calculate( contentsStart: $contentsStart, contentsEnd: $contentsEnd, fileLength: $fileLength,);// $range === [0, $contentsStart, $contentsEnd, $fileLength - $contentsEnd]// Segment 1: file start → just before the signature value// Segment 2: just after the signature value → end of file// The signature value itself is the gap. It is never hashed.
$signedMessage = ByteRangeCalculator::extractSignedData($pdfBytes, $range);// $signedMessage is segment 1 concatenated with segment 2 — exactly the// bytes the cryptographic digest is computed over.Промежуток между двумя сегментами — это значение подписи. Оно не может быть частью собственного дайджеста, поэтому диапазон состоит из двух частей, а не из одной.
Распространённое заблуждение
Заголовок раздела «Распространённое заблуждение»Ловушка — считать, что действительная подпись означает, будто подписан был весь файл, который вы видите. Это не так. Это означает, что байты внутри объявленного диапазона не изменены. Более поздняя редакция может законно добавить содержимое — вторую подпись, данные формы, материал проверки — вне этого диапазона. Первая подпись остаётся действительной и ничего не говорит о добавлении. Корректная программа просмотра сообщает вам, что подпись охватывает “документ в том виде, в каком он существовал на момент подписания”, а не “каждый байт на экране”. Если считать эти два понятия одним и тем же, подписанный документ получает неподписанное содержимое, которое выглядит подписанным.
Пределы и границы
Заголовок раздела «Пределы и границы»На этой странице объясняется структура, а не доверие. Корректно сформированные
ByteRange и объект CMS сообщают вам, что байты не изменены и какой ключ их подписал.
Сами по себе они не говорят, принадлежит ли этот ключ тому, кого вы
предполагаете, был ли его сертификат действителен на момент подписания и не был ли он впоследствии
отозван. Это относится к работе с путём сертификации и отзывом, рассмотренной в
Правильная проверка подписи.
Эта страница также не охватывает то, когда произошло подписание, с участием какой-либо
независимой стороны. Самостоятельно заявленное время подписания не является доверенным временем —
см. Метки времени и доверенное время.
NextPDF строит структуру, описанную здесь; сертификаты, якоря доверия
и служба меток времени предоставляются вашей средой развёртывания, а не движком.
По уровням движок предоставляет возможность построить структуру:
| Edition | Availability |
|---|---|
| Core | PAdES B-B: словарь подписи, ByteRange фиксированной ширины и откреплённый объект CMS SignedData, описанный на этой странице. |
| Pro | Добавляет PAdES B-T — доверенную метку времени для значения подписи — поверх той же структуры. |
| Enterprise | Добавляет долгосрочные профили (B-LT, B-LTA): встроенный материал проверки и метки времени документа, наложенные на ту же основу диапазона байтов. |
Связанные документы
Заголовок раздела «Связанные документы»- Инкрементальные обновления и почему они важны — почему добавление, а не перезапись, сохраняет диапазон байтов первой подписи.
- Базовые профили PAdES — что накладывается поверх этой структуры и какой профиль нужен для обязательства.
- Долгосрочная проверка — как встраиваются доказательства проверки, чтобы подпись оставалась проверяемой годами.
Глоссарий
Заголовок раздела «Глоссарий»- Словарь подписи — словарь PDF, который именует обработчик подписи,
SubFilter,ByteRangeи значениеContents. ByteRange— массив пар целых чисел(offset, length), объявляющий точные байты, которые охватывает дайджест подписи.Contents— шестнадцатеричная запись, хранящая значение подписи (для PDF 2.0 — откреплённый объект CMSSignedData); она исключается из собственного дайджеста.- CMS
SignedData— структура Cryptographic Message Syntax (RFC 5652), несущая сертификат подписавшего и байты подписи. - PAdES — PDF Advanced Electronic Signatures: профиль ETSI подписей CMS для PDF, определённый в серии ETSI EN 319 142.
- Подпись одобрения — подпись с разрешением
MDP, равным0; она удостоверяет содержимое, не ограничивая дальнейшие изменения. - Подпись сертификации — подпись с разрешением DocMDP (
MDP1–3), которая ограничивает, какие из дальнейших изменений сохраняют соответствие документа.