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

Проверка подписи: криптографическая проверка AdES / PAdES

NextPDF Enterprise криптографически проверяет цифровые подписи. Сторона проверки читает Cryptographic Message Syntax (CMS) SignedData или токен метки времени Request for Comments (RFC) 3161 из PDF, заново вычисляет дайджесты, проверяет подписи, связывает каждую подпись с её сертификатом подписания и проверяет цепочку сертификатов, включая обработку политик сертификатов, относительно хранилища якорей доверия, предоставленного вызывающей стороной. На этой странице описано поведение: что проверяется, что отклоняется по принципу fail-closed, какие алгоритмы поддерживаются и где проходит граница доверия.

Это отличается от Validation, где выполняются только структурные проверки политик в режиме чтения и намеренно не выполняется никакая криптография. Это также аналог на стороне проверки для производителя подписей, который записывает структуры PDF Advanced Electronic Signatures (PAdES) B-LT / B-LTA.

Окно терминала
composer require nextpdf/enterprise:^3

Проверка опирается на доказательства и работает по принципу fail-closed: проверка, которую нельзя положительно установить, не даёт положительного результата. Перечисленные ниже элементы складываются в единый итог, который несёт ValidationReport.

Криптографическая проверка CMS / токена метки времени. Автономный строгий DER-стек с определённой длиной разбирает CMS SignedData и токен метки времени RFC 3161. Токен принимается только тогда, когда содержит ровно один SignerInfo, его подписанные атрибуты строго разобраны, сертификат подписавшего разрешён, атрибут message-digest совпадает с заново вычисленным дайджестом, обязательная привязка к сертификату подписания (ESS signing-certificate-v2) выполнена, а подпись SignerInfo проверяется по подписанным атрибутам после повторного DER-кодирования. Правило сопоставления дайджестов следует модели проверки RFC 5652 §5.6 / §5.4: получатель заново вычисляет дайджест содержимого, и подпись действительна только тогда, когда это значение равно подписанному атрибуту messageDigest. Верификатор никогда не доверяет дайджесту, предоставленному производителем.

Проверка сертификата TSA на момент genTime. genTime метки времени — это момент UTC, когда токен был создан (RFC 3161 §2.4.2). Сертификат подписания TSA проверяется именно на этот момент, а не на “сейчас”: его расширенное использование ключа должно быть единственным критическим id-kp-timeStamping (RFC 3161 §2.3), а окно действия, цепочка, происхождение якоря доверия и статус отзыва оцениваются относительно genTime. Структурно правильная цепочка, которая не доходит до настроенного якоря доверия, никогда не может обосновать положительный результат.

Отсоединённые базовые подписи документов PAdES. Специализированный экстрактор выполняет полноценную базовую проверку Advanced Electronic Signatures (AdES) / PAdES для отсоединённой подписи документа: дайджест сообщения заново вычисляется по подписанному диапазону байтов и сравнивается, подпись проверяется, а привязка к сертификату подписания обязательна. Это заменяет прежний резервный вариант, основанный только на структуре. Верификатор меток времени и экстрактор подписей документов используют общий валидатор ESS issuer-and-serial, поэтому разбор привязки к сертификату не расходится.

Архивная цепочка покрытия DocTimeStamp. validateArchivalTimestampChain() проверяет цепочку доверенных токенов DocTimeStamp по диапазонам байтов PDF как архивное доказательство B-LTA. Отпечаток каждого токена привязан к фактическим байтам ByteRange, которые он покрывает, цепочка соблюдает строгий порядок ETSI, цепочка TSA каждого токена привязана к якорю доверия, и цепочка должна покрывать файл до его маркера конца файла. Полностью пройденный результат возможен только для полной, привязанной к якорю доверия цепочки, покрывающей файл до EOF.

Обработка политик сертификатов (RFC 5280 §6.1.4). Проверка пути применяет полную обработку политик сертификатов: дерево узлов политик, сопоставление политик с резервным вариантом anyPolicy и свёртку policyConstraints / inhibitAnyPolicy, опираясь на DER-читатель расширений политик с поведением fail-closed. Переменные состояния обработки пути explicit_policy и inhibit_anyPolicy (RFC 5280 §6.1.2) определяют, требуется ли непустое дерево действительных политик; завершающий шаг пересекает дерево действительных политик с user-initial-policy-set (RFC 5280 §6.1.4). Без обязательных политик и при принятом anyPolicy обработка не ограничена; это поведение по умолчанию не изменилось.

Сторона проверки принимает приведённый ниже набор алгоритмов и отклоняет по принципу fail-closed всё, что в него не входит: неподдерживаемый алгоритм означает отклонённую проверку, а не тихий пропуск.

СемействоПоддержкаПримечания
RSA (PKCS#1 v1.5) — схема подписиrsaEncryption с SHA-2 и sha*WithRSAEncryption (OID)Принимается
ECDSAкривые P-256, P-384, P-521Принимается
RSASSA-PSS (схема подписи)Не поддерживается → fail-closed
EdDSA (схема подписи)Не поддерживается → fail-closed
Дайджесты SHA-3Не поддерживается → fail-closed
SHA-1Слабый алгоритм: базовая подпись, проверяемая под SHA-1, понижается до сбоя по криптографическим ограничениям, а не до прохождения

Сторону проверки используют через публичный движок и контракты Core / Pki. Конкретные классы стратегий внутренние.

ТипВидРоль
AdESValidationEngineклассТочка входа на стороне проверки: проверка подписи и архивной цепочки.
AdESValidationEngine::validateArchivalTimestampChain()методПроверить доверенную цепочку покрытия DocTimeStamp по диапазонам байтов PDF.
ValidationReportрезультатСтруктурированный итог: общий статус плюс выводы по каждой проверке.
PathValidatorInterfaceинтерфейс (NextPDF\…\Pki)SPI проверки пути сертификации, от которого зависит движок.
PathValidationOptionsобъект-значениеПараметры управления обработкой политик: requireExplicitPolicy, inhibitAnyPolicy, inhibitPolicyMapping, maxPolicyFanout.
TrustAnchorStoreInterfaceинтерфейсПредоставленный вызывающей стороной набор доверенных якорей, относительно которого оценивается цепочка.

У метода проверки архивной цепочки такая сигнатура:

public function validateArchivalTimestampChain(
string $pdfBytes,
array $dssData = [],
?TrustAnchorStoreInterface $anchors = null,
): ValidationReport;

Метод возвращает полностью пройденный результат только тогда, когда цепочка DocTimeStamp полностью проверена, привязана к якорю доверия и покрывает файл до его маркера EOF.

CertificateChainValidator::validate() принимает набор начальных политик (user-initial-policy-set из RFC 5280). По умолчанию это anyPolicy; он не накладывает ограничений, поэтому обычная цепочка не затрагивается. Передайте явный набор или установите requireExplicitPolicy, чтобы потребовать непустое дерево действительных политик.

use NextPDF\Enterprise\Security\Validation\AdESValidationEngine;
$report = $engine->validateArchivalTimestampChain($pdfBytes, [], $trustAnchors);
if ($report->isTotalPassed()) {
// A complete, trust-anchored, EOF-covering DocTimeStamp chain.
}
use NextPDF\Enterprise\Security\Validation\AdESValidationEngine;
use Psr\Log\LoggerInterface;
final readonly class ArchivalEvidenceCheck
{
public function __construct(
private AdESValidationEngine $engine,
private LoggerInterface $logger,
) {}
public function check(string $pdfBytes, TrustAnchorStoreInterface $anchors): bool
{
$report = $this->engine->validateArchivalTimestampChain($pdfBytes, [], $anchors);
foreach ($report->findings as $finding) {
$this->logger->info('archival.finding', [
'check' => $finding->checkId,
'status' => $finding->status->value,
]);
}
// A positive result proves byte-range coverage by a trusted timestamp
// chain — it is one input to your decision, not a legal conclusion.
return $report->isTotalPassed();
}
}

Изменения поведения и заметки по обновлению

Заголовок раздела «Изменения поведения и заметки по обновлению»

Сторона проверки перешла от приёма по структуре / времени к полной криптографической проверке. Если вы полагаетесь на прежнее, более мягкое поведение, учтите эти изменения.

  • Fail-closed для распознаваемой, но непроверяемой метки времени. Токен DocTimeStamp или архивный токен, который ранее проходил по структурным и временным признакам, теперь требует полной криптографической проверки: подписи, message-digest и привязки к сертификату подписания. Токен, который не проходит проверку, больше не даёт положительного доказательства существования; его результат становится неопределённым или неуспешным.
  • Базовые подписи SHA-1 понижаются, а не проходят. Базовая подпись документа, которая проверяется, но использует SHA-1, сообщается как сбой по криптографическим ограничениям, а не как полное прохождение.
  • Обработка политик сертификатов RFC 5280 §6.1.4 применяется в обязательном порядке. Цепочка, у которой explicit_policy достигает нуля при пустом дереве действительных политик, теперь не проходит, в том числе если это вызвано policyConstraints requireExplicitPolicy внутри цепочки. Цепочки по умолчанию, без ограничений (без обязательных политик, с принятым anyPolicy) не затрагиваются.
  • Изменение сигнатуры конструктора (нарушение обратной совместимости). AdESValidationEngine::__construct() теперь объявляет параметр $chainValidator как SPI Pki\PathValidatorInterface, со значением по умолчанию, которое лениво устанавливается в Pki\CertificateChainValidator::withDefaults(). Ранее это был конкретный Ltv\CertificateChainValidator. Вызывающая сторона, которая внедряла конкретный валидатор LTV, должна вместо этого внедрить реализацию SPI Pki. Валидатор Pki оборачивает тот же структурный движок пути и добавляет ограничения имён и обработку политик; для входных данных, соответствующих настройкам по умолчанию, он не меняет поведение.
  • Неподдерживаемый алгоритм ≠ неопределённость. RSASSA-PSS, EdDSA и SHA-3 отклоняются по принципу fail-closed, а не переводятся в неопределённое состояние. Если ваши подписанты используют их, эта сторона проверки не вернёт положительный результат.
  • Доверие относительно якоря. Проверка всегда относительна к хранилищу якорей доверия, которое вы предоставляете. Пустой или неправильный набор якорей даёт результат “не доверено” независимо от криптографической корректности.
  • genTime, а не сейчас. Сертификат TSA оценивается на момент genTime токена. Сертификат TSA, который с тех пор истёк, всё ещё может обосновать токен, созданный, пока он был действителен; сертификат, ещё не действительный на момент genTime, — не может.
  • Покрытие до EOF. Архивная цепочка должна покрывать документ до его маркера EOF. Метка времени, покрывающая лишь префикс файла, не устанавливает покрытие всего документа.
  • “Не доказано отозванным” — это не Good. Вердикт Valid требует достоверно неотозванного статуса. Если и OCSP, и CRL возвращают Unknown или Unavailable, даже криптографически корректная подпись с проверенной цепочкой и якорем доверия разрешается в Indeterminate. Предоставьте встроенный материал OCSP/CRL со статусом Good для сертификата подписавшего, чтобы достичь Valid.

Проверка выполняется внутри процесса по предоставленным байтам PDF и встроенному материалу проверки; стоимость растёт с длиной цепочки и числом меток времени. Проверка не делает сетевых обращений. Материал для проверки отзыва и доверия берётся из данных, которые предоставляет вызывающая сторона или которые встроены в документ. Проверка детерминирована: одни и те же входные данные и одни и те же якоря доверия дают один и тот же отчёт.

  • Fail-closed — это поведение по умолчанию. Каждый шаг приёма отклоняет материал, который не может положительно проверить. Это не позволяет документу заявлять действительность, которую движок никогда не устанавливал.
  • Дописывание после метки времени отражается покрытием до EOF. Поскольку отпечаток каждой архивной метки времени привязан к фактическим байтам ByteRange и цепочка должна доходить до EOF, содержимое, дописанное после метки времени, не покрывается ею и не получает её доказательственного веса.
  • Считайте входные данные враждебными. Байты PDF, встроенный CMS и токены меток времени из недоверенных источников разбираются строгим DER-читателем с определённой длиной, который отклоняет некорректные кодировки и кодировки неопределённой длины.

Проверка выполняется внутри процесса и локально, без сетевого ввода-вывода. Сертификаты и подписи несут идентификационные данные субъекта; применяйте собственные средства контроля хранения и минимизации к отчётам и любым извлечённым данным сертификатов.

Безопасная телеметрия и очистка журналов

Заголовок раздела «Безопасная телеметрия и очистка журналов»

Выводы содержат идентификаторы и статусы проверок. Некоторые диагностические данные могут включать имена субъектов сертификатов или серийные номера; очищайте или скрывайте эти поля, прежде чем пересылать журналы в общие приёмники.

Указывайте эти границы в выводе для пользователя, чтобы положительный результат не трактовался слишком широко.

  • validateArchivalTimestampChain() доказывает покрытие диапазона байтов, а не достижимость по xref. Он устанавливает, что доверенная цепочка меток времени криптографически покрывает диапазоны байтов документа до EOF. Он не выполняет анализ на уровне xref или анализ достижимости объектов startxref; это намеренно вне области применения. Правило покрытия до EOF вместе с привязкой к якорю доверия учитывает атаки дописывания после метки времени, а не анализ графа объектов.
  • Намеренно вне области применения. Записи доказательств (RFC 4998 / RFC 6283); проверка токенов меток времени RSASSA-PSS, EdDSA или SHA-3; интеграция с доверенными списками (TSL) и квалифицированными TSA; а также онлайн-получение информации об отзыве TSA этой стороной проверки не предоставляются. Отзыв оценивается по материалу, уже доступному верификатору.
ПоведениеСсылкаСтатус
Значение подписи / токен метки времени хранятся в кодировке DER в /ContentsISO 32000-2 §12.8.1Разобрано и проверено
Словарь метки времени документаISO 32000-2 §12.8.5Читается для архивной цепочки
Получатель заново вычисляет дайджест содержимого; он должен быть равен атрибуту messageDigestRFC 5652 §5.6 / §5.4Применяется
Сертификат TSA несёт единственный критический id-kp-timeStamping (EKU)RFC 3161 §2.3Проверяется на момент genTime
genTime — это момент создания по UTCRFC 3161 §2.4.2Используется как момент проверки
Переменные состояния обработки политик (explicit_policy, inhibit_anyPolicy)RFC 5280 §6.1.2Обрабатывается
Завершающий шаг пересекает дерево действительных политик с user-initial-policy-setRFC 5280 §6.1.4Применяется
Записи DSS и метки времени документа для долгосрочных подписейETSI EN 319 142-2 §5.5Проверяется как архивное доказательство

Все пункты приведены в пересказе. NextPDF не воспроизводит нормативный текст; за авторитетной формулировкой обращайтесь к опубликованным стандартам. NextPDF не делает заявления о сертификации AdES / PAdES. Сторона проверки реализует криптографические проверки, описанные цитируемыми спецификациями; это не сертифицированная служба проверки, и она не выдаёт стороннего удостоверения.

Когда активен профиль Enterprise FIPS, ограничения применяются к алгоритмам дайджеста и подписи, которые принимает верификатор. Логика проверки, включая повторное вычисление дайджеста, проверку подписи, привязку к сертификату и проверку пути, не изменяется.

АктивПротивникРискМеры защиты
Токен метки времениПоддельный или изменённый токенЛожное доказательство существованияПолная криптографическая проверка; fail-closed для всего непроверяемого
Сертификат TSAНедоверенный издательМнимое доверие, которое верификатор не должен утверждатьЦепочка проверена до предоставленного вызывающей стороной якоря на момент genTime; недоверенная цепочка никогда не проходит
Байты документаДописывание после метки времениСодержимое получает вес метки времени без покрытияОтпечаток привязан к фактическим байтам ByteRange + правило покрытия до EOF
Слабый алгоритмПонижение до SHA-1 / неподдерживаемой схемыСлабая подпись, распознанная как действительнаяSHA-1 понижается; RSASSA-PSS / EdDSA / SHA-3 fail-closed

Эта сторона проверки — функция Enterprise и поставляется в пакете nextpdf/enterprise. NextPDF Core обнаруживает наличие подписи и создаёт подписи B-B / B-T, но не предоставляет эту криптографическую сторону проверки. Получить лицензию.

Сторона проверки ограничена редакцией Enterprise (license_feature_flag: enterprise). Она разрешается через контракты Core и Pki; публичный API приложения не меняется при обновлении редакции.

  • Токен CMS или метки времени принимается только при наличии ровно одного SignerInfo, строго разобранных подписанных атрибутов, разрешённого сертификата подписавшего, совпадающего message-digest, обязательной привязки к сертификату подписания и проверяемой подписи SignerInfo.
  • Сертификат TSA проверяется на момент genTime токена: единственный критический EKU id-kp-timeStamping, окно действия, привязанная к якорю доверия цепочка и статус отзыва.
  • Вердикт Valid дополнительно требует достоверно неотозванного статуса: по крайней мере одного авторитетного Good (проверенного ответа OCSP со статусом Good или свежего CRL, помещающего серийный номер вне неистёкшего списка). Статус, который лишь “не доказано отозванным”, когда и OCSP, и CRL являются Unknown или Unavailable, разрешается в Indeterminate, но никогда в Valid (ETSI EN 319 102-1: revocation status-unavailable → INDETERMINATE). Поскольку резервный путь CRL удостоверяет только свежесть списка, а не неотозванность конкретного серийного номера, цепочка только с CRL без Good OCSP обычно бывает Indeterminate.
  • validateArchivalTimestampChain() возвращает полностью пройденный результат только для полной, привязанной к якорю доверия цепочки DocTimeStamp, покрывающей файл до EOF; он доказывает покрытие диапазона байтов, а не достижимость по xref.
  • Обработка политик сертификатов следует RFC 5280 §6.1.4; цепочки по умолчанию, без ограничений, не затрагиваются.
  • Поддерживаемые алгоритмы — RSA (PKCS#1 v1.5 с SHA-2) и ECDSA (P-256/384/521); RSASSA-PSS, EdDSA и SHA-3 отклоняются по принципу fail-closed; SHA-1 понижается.

Эта публичная страница описывает только внешне наблюдаемое поведение стороны проверки. Она называет публичный движок, контракты Pki / якорей доверия и метод validateArchivalTimestampChain() через поддерживаемый интерфейс. Конкретные внутренние компоненты DER, CMS, обработчика политик и валидатора пути находятся в закрытом справочном разделе под соглашением о неразглашении (NDA).

NextPDF Core обнаруживает наличие подписи и создаёт подписи B-B / B-T, но не проверяет криптографически токены CMS или меток времени, не проверяет архивную цепочку и не выполняет обработку политик RFC 5280 §6.1.4. Развёртывание только с Core не имеет эквивалентной стороны проверки; см. Security / Signing (Core).

NextPDF Pro добавляет стратегии подписания и обработку электронных счетов, но не предоставляет эту криптографическую сторону проверки; проверка архивной цепочки и обработка политик сертификатов поставляются только в nextpdf/enterprise.

Сторона проверки описана на уровне поведения. Строгий стек DER, парсер CMS, обработчик политик и внутренние компоненты валидатора пути находятся вне области публичного интерфейса и здесь не воспроизводятся.

Проверка зависит от хранилища якорей доверия и любого материала об отзыве, который предоставляет вызывающая сторона или который встроен в документ. NextPDF Enterprise оценивает этот материал; он не управляет списком доверия, TSA или службой отзыва. Оператор отвечает за выбор якорей и свежесть встроенного материала об отзыве.

Эта страница помечена export_control_class: legal-review-required; она касается криптографической проверки. Юридическое одобрение требуется до установки флага publish. Положительный результат проверки — это криптографическое утверждение о подписях и метках времени документа. Это не юридическое заключение, не определение квалифицированного статуса eIDAS и не сертификация. NextPDF не делает заявления о сертификации AdES / PAdES. Обращайтесь к собственным консультантам по соответствию и юристам по вопросам ваших регуляторных обязательств.