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

Enterprise редакция

Проверка подписи: криптографическая сторона проверки 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.

Эта возможность поставляется в NextPDF Enterprise (nextpdf/enterprise) и активируется лицензионным конвертом уровня Enterprise. Развёртывание без такого права доступа не загружает классы этой возможности. Сравнить редакции и получить лицензию.

Окно терминала
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 и OID sha*WithRSAEncryptionПринимается
ECDSAкривые P-256, P-384, P-521Принимается
RSASSA-PSSНе поддерживается → fail-closed
EdDSAНе поддерживается → fail-closed
Дайджесты SHA-3Не поддерживается → fail-closed
SHA-1Слабый: базовая подпись, проверяемая под SHA-1, понижается до сбоя по криптографическим ограничениям, а не до прохождения

Сторона проверки по замыслу работает по принципу fail-closed. Она возвращает положительный результат только для материала, который может положительно установить; всё остальное отображается в неопределённый или неуспешный итог. Это отвергает соблазнительный вариант по умолчанию — доверять правильно оформленному, правдоподобно выглядящему токену. Доверие всегда относительно хранилища якорей, предоставленного вызывающей стороной, поэтому движок никогда не утверждает доверие, которое ему не было дано. Сертификат метки времени оценивается на её genTime, а не «сейчас», потому что именно тогда токен был фактически создан. Неподдерживаемые алгоритмы отклоняются сразу, а не откладываются, поэтому слабая схема не может проскользнуть как неопределённое прохождение.

Предыстория проектирования: Как правильно проверять подпись.

Сторону проверки используют через публичный движок и контракты 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 оборачивает тот же структурный движок пути и добавляет ограничения имён и обработку политик; для входных данных, соответствующих настройкам по умолчанию, он не меняет поведение.
  • Строгая привязка отпечатка метки времени подписи (нарушение обратной совместимости). Метка времени подписи PAdES B-T теперь при проверке привязывается к подписи, которую она покрывает: отпечаток сообщения токена должен быть равен хешу значения подписи SignerInfo (RFC 3161 Appendix A; ETSI EN 319 122-1 §5.3). Правило применяется как на пути проверки по времени, так и на пути проверки по долгосрочным данным. Отсутствующий или дублированный атрибут метки времени подписи — это сбой формата; отпечаток, который не привязывается, или токен, который не проходит проверку, даёт результат неопределённости/порядка меток времени; SHA-1 или нераспознанный алгоритм отпечатка даёт результат неопределённости/криптографических ограничений. На долгосрочном пути сертификат TSA привязанного токена дополнительно оценивается на момент его genTime; при проверке доверия по умолчанию без хранилища это разрешается в Indeterminate, пока не настроено хранилище якорей доверия, — намеренная установка fail-closed по умолчанию. Документ, метка времени подписи которого создана версией NextPDF, выпущенной до этого исправления, привязана к другому входу и не может пройти эту проверку; повторно подпишите и заново поставьте метку времени, чтобы восстановить положительное время B-T.
  • Неподдерживаемый алгоритм ≠ неопределённость. 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
  • Токен 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 понижается.

Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую поверхность публичного API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов runbook и префиксы тикетов вне области применения.

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 или службой отзыва. Оператор отвечает за выбор якорей и свежесть встроенного материала об отзыве.

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