Перейти к содержимому

Правильная проверка подписи

Spec: RFC 5280, §6 Spec: RFC 6960 Spec: RFC 5652 Evidence: Test-backed

“Подпись действительна” обычно означает, что проверено только одно: математика сошлась. При правильной проверке контролируются как минимум пять независимых вещей, и любая из них может дать сбой так, что зелёная галочка потеряет смысл. На этой странице приведён полный набор проверок и объясняется, почему частичный ответ опасен.

Одно булево значение — самый опасный результат во всей этой теме. Оно подталкивает читателя воспринимать “действительна” как “заслуживает доверия”, хотя “действительна” может означать лишь, что байты не были изменены и подпись сошлась с ключом из сертификата, который истёк три года назад, был отозван в прошлом месяце и выстраивается в цепочку к удостоверяющему центру, который вы не признаёте. Каждое из этих условий — отдельная проверка. Программа, возвращающая одно булево значение, негласно решила, какие проверки важны, и сделала это за вас. В регулируемой или договорной среде довод “инструмент сказал, что действительна” не защитит, если инструмент проверил только самое дешёвое свойство.

Полная проверка отвечает на пять отдельных вопросов. Они независимы: успешное прохождение одной проверки ничего не говорит об остальных:

  1. Целостность — дают ли подписанные байты по-прежнему тот же хеш, который покрывает подпись? (Пересчитайте дайджест по диапазону байтов и сравните.)
  2. Подлинность — проверяется ли криптографическая подпись по открытому ключу из сертификата подписи над подписанными атрибутами?
  3. Путь сертификации — выстраивается ли этот сертификат в цепочку к якорю доверия, который выбрали вы, и действительно ли каждое звено?
  4. Время — был ли сертификат в пределах своего срока действия в соответствующий момент времени и является ли это время доверенным, а не заявленным самим подписантом?
  5. Отзыв — был ли сертификат не отозван на тот момент согласно данным (OCSP/CRL), которые вы действительно можете получить или которые встроены?

Вердикт “действительна”, при котором выполнены не все пять проверок, — это неполный ответ, который выглядит как полный.

Позиция NextPDF такова: каждый вопрос отдельный, и на каждый нужно ответить явно. Проверка никогда не сводится к одному оптимистичному флагу и не пропускается молча только потому, что оказалась неудобной. Это обеспечивается тестами. Поэтому страница отмечена как подкреплённая тестами, а не подкреплённая стандартом: поведение фиксирует тестовый набор, а не только пункт спецификации.

Целостность и подлинность тестируются сквозным образом. Известный сертификат подписывает реальную структуру подписанных атрибутов, а тестовый набор проверяет подпись соответствующим открытым ключом для нескольких временных векторов. Поэтому изменение, нарушающее каноническую структуру, ломает тест. Проверка пути сертификации закреплена тестами, которые намеренно искажают байт подписи и подтверждают, что результат не действителен, со структурированной причиной — не отброшенным исключением, а явно зафиксированным сбоем. Проверка токена метки времени разбита на отдельные шаги: декодирование, сведения о подписанте, подписанные атрибуты, дайджест сообщения, привязка сертификата, назначение ключа, подпись, момент создания. Каждый шаг тестируется отдельно, поэтому “метка времени проверена” означает, что проверен каждый шаг. Мягкий сбой проверки отзыва (недоступный сервер ответов) отличается, в коде и в тестах, от однозначного “отозван”. Эти два случая никогда не смешиваются в один ответ.

  1. Integrity Recompute the byte-range digest and compare it to the value the signature covers.
  2. Authenticity Verify the cryptographic signature against the certificate’s public key, over the signed attributes — not the raw content.
  3. Certificate path Build and validate the chain to a trust anchor you chose; every link’s signature, validity, and constraints must hold.
  4. Time Confirm the certificate was valid at the relevant instant, and that the instant is trusted time, not the signer’s clock.
  5. Revocation Confirm the certificate was not revoked at that time, using obtainable or embedded OCSP/CRL evidence.
Пять независимых вопросов, на которые по порядку отвечает правильная проверка подписи PDF. Каждый из них отдельный: успешное прохождение одного ничего не говорит об остальных, а пропуск любого делает общий результат неполным.

Evidence: Test-backed Это поведение закреплено тестами, и эти тесты реализуют то, что требуют стандарты.

Целостность определяется Spec: ISO 32000-2, §12.8.1 : дайджест пересчитывается по диапазону байтов и сравнивается с сохранённым значением; любое расхождение означает, что подпись недействительна. Подлинность над подписанными атрибутами покрывает интеграционный тест, который подписывает реальный набор подписанных атрибутов и проверяет его соответствующим открытым ключом для нескольких временных векторов. Вопрос пути сертификации определяется Spec: RFC 5280, §6.1 : действительные пути начинаются от якоря доверия, и Spec: RFC 5280, §6.2 устанавливает, что этот алгоритм определяет минимальные условия действительности пути — модульный тест валидатора пути утверждает, что искажённая подпись даёт valid = false с явной причиной, а не молчаливым принятием.

Порядок проверки отзыва определяется Spec: RFC 6960, §3.2 : прежде чем клиент примет подписанный ответ об отзыве как действительный, он должен убедиться, что собственная подпись ответа действительна и что подписант в данный момент уполномочен, — а Spec: RFC 6960, §4.2.2.2 определяет это полномочие как делегирование id-kp-OCSPSigning, выданное непосредственно соответствующим УЦ. Поэтому ответ об отзыве, который сам не был проверен на соответствие уполномоченному и проверяемому подписанту, бессмыслен. Проверка привязки сертификата определяется Spec: RFC 5035, §5.4.2 : если хеш сертификата в подписанном атрибуте signing-certificate-v2 не совпадает с сертификатом, использованным для проверки подписи, подпись должна считаться недействительной. Это закрывает брешь подмены, при которой подпись успешно проверяется по сертификату, выбранному злоумышленником. Сам токен метки времени проверяется в стиле Spec: RFC 5652 как объект CMS, шаг за шагом; каждый шаг тестируется отдельно.

Здесь важен не вызов API, а вопросы, на которые нужно уметь ответить прежде, чем действовать на основании результата. Воспринимайте это как контрольный список, по которому вас будут спрашивать на ревью.

<?php
declare(strict_types=1);
// A correct validation produces a structured outcome, not one boolean.
// Before you trust a signature, you must be able to answer ALL of these:
//
// integrity : Does the byte-range digest still match? (tamper check)
// authenticity: Does the signature verify over the SIGNED ATTRIBUTES,
// not just the content?
// path : Does the certificate chain to a trust anchor YOU chose,
// with every link valid at the relevant time?
// time : Is the relevant time TRUSTED (a timestamp), or merely the
// signer's self-asserted clock?
// revocation : Was the certificate not revoked at that time, by evidence
// you obtained or that the document embedded?
//
// "valid: true" without an answer to every line above is an incomplete
// result. A path-validation outcome carries a `valid` flag AND a structured
// `reasons` list precisely so a failure says WHY — never a bare false.

Если по какой-либо строке ответ — “я не знаю”, честный статус — не “действительна”. Это “ещё не определено”, и считать эти два состояния одним и тем же — именно та ошибка, ради предотвращения которой существует эта страница.

Ловушка — приравнять “криптографически действительна” к “заслуживает доверия”. Целостность и подлинность вместе доказывают только то, что эти байты были подписаны владельцем этого ключа. Они ничего не говорят о том, был ли сертификат этого ключа доверенным, действующим или неотозванным. Документ, подписанный самостоятельно сгенерированным сертификатом, может быть “криптографически действителен” и при этом не стоить ничего. Обратная ловушка — трактовать неопределённый результат проверки отзыва (сервер ответов недоступен) как успех или как провал. Это ни то ни другое. Это неизвестно, и правильный валидатор сообщает об этом как о неизвестном, а не гадает в ту или иную сторону. Зелёная галочка, скрывающая, какие из пяти проверок действительно выполнялись, — это не результат проверки. Это решение, которое кто-то другой принял за вас.

NextPDF выполняет и тестирует структурные и криптографические проверки. Он не выбирает за вас якоря доверия и не гарантирует политику, надстроенную над ними. Каким сертификатам доверять — это решение уровня развёртывания, которое движок не может принять за вас. Цепочка, успешно выстроенная к якорю, которому не следовало доверять, всё равно остаётся проверкой, на которую нельзя полагаться. Данные об отзыве можно проверить, только если они доступны для получения или встроены. Недоступный сервер ответов даёт “неопределённо”, и превращение этого в вердикт — выбор политики, а не движка. Эта страница описывает набор проверок, а не юридическую достаточность. Имеет ли проверенная подпись то или иное юридическое значение, зависит от сертификата, подписанта, юрисдикции и обязательства. Как встроенные данные сохраняют возможность отвечать на эти вопросы с течением времени, рассказано в разделе Долгосрочная проверка; механизм диапазона байтов, лежащий в основе проверки целостности, описан в разделе Как подписи размещаются в PDF.

Доступность возможностей проверки по тарифным планам:

Набор проверок подписи — edition availability
Edition Availability
Core

Целостность и подлинность над подписанными атрибутами, а также проверка пути сертификации по RFC 5280 §6 относительно предоставленного якоря доверия.

Pro

Добавляет проверку токена метки времени по RFC 3161: вопрос доверенного времени, разложенный на независимо проверяемые шаги.

Enterprise

Добавляет оценку отзыва (OCSP/CRL) и проверку относительно встроенного долгосрочного материала, при этом неопределённые результаты отличаются от однозначных.

  • Проверка целостности — пересчёт дайджеста по диапазону байтов и сравнение со значением, которое покрывает подпись.
  • Проверка подлинности — проверка криптографической подписи по открытому ключу сертификата подписи над подписанными атрибутами.
  • Подписанные атрибуты — аутентифицированные атрибуты CMS (content-type, message-digest, signing-time, signing-certificate-v2), над которыми и вычисляется подпись.
  • Проверка пути сертификации — построение и проверка цепочки от сертификата подписи до выбранного якоря доверия (RFC 5280 §6).
  • Якорь доверия — удостоверяющий центр, которому вы решили доверять; корень приемлемого пути.
  • Проверка отзыва — определение того, был ли сертификат отозван в соответствующий момент времени, через OCSP или CRL.
  • Неопределённо — результат проверки отзыва, который не является ни “действителен”, ни “отозван”, поскольку данные не удалось получить; не успех и не провал.