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

Enterprise редакция

Доверенные списки — глубокий справочник

Эта страница — глубокий справочник по поверхности доверенных списков в NextPDF Enterprise. Поверхность — это двенадцать публичных классов пространства имён NextPDF\Enterprise\Security\Tsl. NextPDF\Enterprise\Security\Tsl\TslPolicyEnforcer — оркестрированная точка входа: он возвращает TslDocument только тогда, когда проходят все этапы — HTTP-загрузка, проверка XMLDSig, структурный разбор и шлюз устаревания nextUpdate. Затем TslTrustAnchorProvider::buildBundle() выводит набор якорей доверия из активных служб CA/QC, повторно подтверждая актуальность на переданный вызывающей стороной момент времени до извлечения любого якоря. Каждый сбой поднимает типизированное исключение; ни один этап не деградирует молча. Конвейер поддерживает проверку доверенных списков государств-членов ЕС и якорей доверия из LOTL (List of Trusted Lists), когда они предоставлены вызывающей стороной; автоматическое обнаружение LOTL, опрос и обработка pivot вне области действия.

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

СимволПараметрыПоведение по умолчаниюВозвращаетБросает или завершается сПримечания
TslPolicyEnforcerTslFetcher $fetcher, TslSignatureVerifier $verifier, TslXmlParser $parserОбъединяет загрузку, проверку подписи, разбор и шлюз устаревания в одну точку входаПробрасывает исключения конвейера нижеfinal; по построению отказывает в закрытое состояние
TslPolicyEnforcer::fetchAndVerifystring $urlЗагружает один TSL, затем выполняет verifyXml() над байтамиTslDocumentTslFetchException, NetworkPolicyViolation, TslSignatureException, TslParseExceptionВозвращает только тогда, когда проходят все четыре этапа
TslPolicyEnforcer::verifyXmlstring $xmlПроверяет подпись, разбирает и отклоняет устаревший списокTslDocumentTslSignatureException, TslParseExceptionУстаревание оценивается относительно текущего системного времени
TslFetcherClientInterface $httpClient, RequestFactoryInterface $requestFactory, ?CacheInterface $cache = null, int $defaultTtlSeconds = 3600, int $maxBytes = 16_777_216, NetworkPolicy $networkPolicy = NetworkPolicy::ONLINEЗагрузка TSL/LOTL только по HTTPS с кэшированием по ETagfinal; защита от SSRF блокирует частные, петлевые, link-local и метаданные-хосты с защитой от DNS-rebinding
TslFetcher::fetchstring $urlGET с ревалидацией If-None-Match; кэширует тело плюс ETag с настроенным TTLstring (сырые байты XML)TslFetchException, NetworkPolicyViolationЧитает не более $maxBytes байт; при STRICT_OFFLINE отдаётся только кэшированное тело
TslSignatureVerifierarray $trustAnchorsPem, int $clockTolerance = 0Верификатор XMLDSig, закреплённый на настроенных якорях доверияInvalidArgumentException, когда список якорей пустfinal; списки разрешённого в ALLOWED_SIG_ALG и ALLOWED_DIGEST_ALG
TslSignatureVerifier::verifystring $xmlПроверяет вложенную подпись XMLDSig с отказом в закрытое состояниеstring (PEM сертификата подписанта)TslSignatureException с машиночитаемым кодом причиныСертификаты из KeyInfo сами по себе никогда не доверяются; подписант должен выстраивать цепочку до настроенного якоря
TslXmlParser::parsestring $xmlСтруктурный разбор в TslDocument; не зависит от подписиTslDocumentTslParseExceptionОтклоняет любой DOCTYPE в закрытое состояние до разбора; загружает с LIBXML_NONET; вызывающие стороны должны проверить перед тем, как доверять результату
TslTrustAnchorProvider::buildBundleTslDocument $tsl, DateTimeImmutable $nowСначала подтверждает актуальность, затем собирает сертификаты активных служб CA/QCEnterpriseCaTrustAnchorBundleTslParseExceptionШлюз актуальности предшествует любому извлечению якоря; пустой результат бросает исключение
TslDocumentВосемь продвинутых readonly-свойств (см. ограждение конструктора)Неизменяемый объект-значение разобранного TSLfinal readonly; в исходнике помечен @api
TslDocument::isStaleDateTimeImmutable $nowСравнивает nextUpdate с $now после разбора UTC с отказом в закрытое состояниеboolTslParseExceptionТребует явного обозначения Z или числового смещения
TslDocument::assertFreshDateTimeImmutable $nowБросает, когда список устарел или nextUpdate неразбираемvoidTslParseExceptionШлюз актуальности на границе потребителя
TslDocument::servicesOfTypestring $serviceTypeIdentifierФильтрует службы по URI типа службы ETSIlist<TspService>Не бросает
TslDocument::activeServicesВозвращает только службы в статусе grantedlist<TspService>Не бросаетGranted означает TspService::STATUS_GRANTED
TspServiceВосемь продвинутых readonly-свойствОдна запись службы доверия внутри TSLfinal readonly; константы для статуса и URI типов служб
TspService::isGrantedРавенство статуса с URI grantedboolНе бросает
TspService::isQualifiedCaРавенство типа с URI CA/QCboolНе бросает
TspServiceQualifierstring $qualifierUri, string $criteriaListAssert = 'all', array $policyOidConditions = [], array $keyUsageConditions = []Один квалификатор службы ETSI с необязательными критериямиfinal readonly; константы FOR_ESIG, FOR_ESEAL, FOR_WSA, QSCD_STATEMENT, NO_QSCD
EnterpriseCaTrustAnchorBundlearray $anchorsPem, string $bundleVersion, string $bundleSha256Набор закреплённых якорей; проверяет переданный дайджест против переданных якорей при построенииInvalidArgumentExceptionПолучайте из buildBundle(); не конструируйте вручную; реализует TrustAnchorStoreInterface
EnterpriseCaTrustAnchorBundle::containsFingerprintstring $anchorDerSha256HexПринадлежность якоря по hex SHA-256 над телом DERboolНе бросает
EnterpriseCaTrustAnchorBundle::computeBundleSha256array $anchorsPemКаноническая SHA-256 над конкатенацией PEM с нормализованными переводами строкstringНе бросаетstatic
TslFetchExceptionСигнализирует о неудавшейся загрузке TSLfinal; расширяет RuntimeException
TslParseExceptionСигнализирует о структурном сбое или сбое актуальностиfinal; расширяет RuntimeException
TslSignatureExceptionstring $reason, string $messageСигнализирует о сбое проверки XMLDSig с кодом причиныfinal; публичное readonly $reason (см. коды причин ниже)

TslPolicyEnforcer

public function fetchAndVerify(string $url): TslDocument
public function verifyXml(string $xml): TslDocument

TslFetcher

public function __construct(
private readonly ClientInterface $httpClient,
private readonly RequestFactoryInterface $requestFactory,
private readonly ?CacheInterface $cache = null,
private readonly int $defaultTtlSeconds = 3600,
private readonly int $maxBytes = 16_777_216,
private readonly NetworkPolicy $networkPolicy = NetworkPolicy::ONLINE,
) {}
public function fetch(string $url): string

TslSignatureVerifier

public function __construct(private readonly array $trustAnchorsPem, private readonly int $clockTolerance = 0)
public function verify(string $xml): string

TslXmlParser

public function parse(string $xml): TslDocument

TslTrustAnchorProvider

public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundle

TslDocument

public function __construct(
public string $schemeTerritory,
public string $schemeOperatorName,
public string $tslType,
public int $sequenceNumber,
public string $issueDateTime,
public string $nextUpdate,
public array $tspServices,
public string $rawXmlSha256,
) {}
public function isStale(DateTimeImmutable $now): bool
public function assertFresh(DateTimeImmutable $now): void
public function servicesOfType(string $serviceTypeIdentifier): array
public function activeServices(): array

TspService

public function __construct(public string $tspName, public string $serviceName, public string $serviceTypeIdentifier, public string $serviceStatus, public string $statusStartingTime, public string $serviceCertificatePem, public array $qualifiers, public array $additionalServiceInformation) {}
public function isGranted(): bool
public function isQualifiedCa(): bool

TspServiceQualifier

public function __construct(public string $qualifierUri, public string $criteriaListAssert = 'all', public array $policyOidConditions = [], public array $keyUsageConditions = []) {}

EnterpriseCaTrustAnchorBundle

public function __construct(public array $anchorsPem, public string $bundleVersion, public string $bundleSha256)
public function containsFingerprint(string $anchorDerSha256Hex): bool
public static function computeBundleSha256(array $anchorsPem): string

TslSignatureException

public function __construct(public readonly string $reason, string $message)

Коды причин TslSignatureException: missing_signature, untrusted_signer, invalid_signature, digest_mismatch, unsupported_algorithm, unsupported_transform, expired_anchor.

  • Порядок конвейера фиксирован: загрузка, проверка XMLDSig, структурный разбор, шлюз устаревания. TslPolicyEnforcer возвращает TslDocument только тогда, когда все четыре этапа успешны. Доверенный список подписывается своим оператором схемы, чтобы полагающиеся стороны могли проверить подлинность и целостность — ETSI TS 119 612 §5.7.1.
  • TslXmlParser по замыслу не зависит от подписи. Вызывающие стороны должны проверить подпись, прежде чем доверять любому разобранному полю. TslPolicyEnforcer::verifyXml() обеспечивает этот порядок.
  • Инвариант актуальности обеспечивается на каждой границе потребителя. Список, у которого nextUpdate прошёл, считается просроченным и отклоняется — ETSI TS 119 612 §5.3.15. verifyXml() контролирует относительно текущего системного времени; TslDocument::assertFresh() и buildBundle() контролируют относительно переданного вызывающей стороной момента времени.
  • Разбор актуальности отказывает в закрытое состояние. Поля даты-времени — это значения ISO 8601 в UTC с явным обозначением — ETSI TS 119 612 §5.1.3. nextUpdate без явного Z или числового смещения поднимает TslParseException; значение никогда не переинтерпретируется в местном часовом поясе сервера.
  • buildBundle() вызывает assertFresh($now) до извлечения любого якоря, затем допускает только службы, которые одновременно granted и CA/QC. Granted и withdrawn — это URI статусов квалифицированной службы — ETSI TS 119 612 §5.5.4. CA/QC — это URI типа службы квалифицированного УЦ — ETSI TS 119 612 §5.5.1.1.
  • Версия набора выводится из территории схемы и порядкового номера TSL. Порядковый номер монотонен по релизам — ETSI TS 119 612 §5.3.2. Дайджест набора — это каноническая SHA-256 над PEM якорей, а containsFingerprint() отвечает на вопрос принадлежности по DER SHA-256.
  • Верификатор доверяет только настроенным якорям. Сертификаты, найденные в KeyInfo, служат листом подписанта и кандидатами-промежуточными; цепочка должна достичь настроенного якоря в пределах глубины 8, каждое звено должно быть темпорально действительным, а выпускающий сертификат должен нести basicConstraints cA=TRUE (плюс keyCertSign, когда присутствует keyUsage).
  • Профиль проверки — это список разрешённого: RSA или ECDSA с SHA-256, SHA-384 или SHA-512; методы дайджеста SHA-256, SHA-384 или SHA-512; только исключительная канонизация; и в точности пара трансформаций вложенной подписи плюс исключительная C14N на покрывающем список ds:Reference. Всё остальное завершается с unsupported_algorithm или unsupported_transform.
  • TslFetcher отклоняет URL не-HTTPS и применяет защиту от SSRF до любого исходящего трафика. При NetworkPolicy::STRICT_OFFLINE он отдаёт ранее кэшированное тело или поднимает NetworkPolicyViolation; ни один исходящий запрос никогда не отправляется.
  • Устаревший список. TslParseException из verifyXml(), assertFresh() или buildBundle() означает, что источник доверия непригоден. Трактуйте это как операционный сбой обновления, а не как вердикт по подписи.
  • Неканонический nextUpdate. Значение без явного Z или числового смещения бросает вместо снисходительного разбора. ETSI TS 119 612 §5.1.3 предписывает UTC-форму Z; шлюз также принимает явное числовое смещение и отклоняет всё остальное.
  • Дрейф времени использования. verifyXml() контролирует во время проверки; документ, удерживаемый в памяти после nextUpdate, всё равно не проходит более поздний шлюз buildBundle($tsl, $now).
  • Пустая конфигурация якорей. TslSignatureVerifier отказывается от построения с пустым списком якорей (InvalidArgumentException).
  • Нет пригодных служб. Свежий список без granted-служб CA/QC поднимает TslParseException из buildBundle(); пустой набор никогда не производится.
  • Оффлайн-режим. STRICT_OFFLINE без кэшированного тела поднимает NetworkPolicyViolation. Поиск в кэше предшествует проверке политики, поэтому кэшированный список сохраняет работу валидации в изолированной сети.
  • Слишком большой или пустой ответ. fetch() читает не более $maxBytes байт (по умолчанию 16 MiB); усечённый список затем не проходит проверку дайджеста далее по конвейеру. Пустое тело поднимает TslFetchException.
  • DOCTYPE в XML. Любой DOCTYPE отклоняется до того, как libxml построит таблицу сущностей, и снова после загрузки. Это закрывает входные классы XXE и раскрытия сущностей (billion-laughs).
  • Множественные подписи. До вычисления дайджеста удаляется только проверенная вложенная ds:Signature; соседние подписи и контрподписи сохраняются. Дополнительные ссылки XAdES разрешены, но ровно одна ds:Reference должна покрывать корень документа.
  • Просроченный материал цепочки. Просроченный или ещё не действительный подписант, промежуточный или якорь завершается с причиной expired_anchor. clockTolerance симметрично расширяет окно приёма и по умолчанию равен 0.

Список разрешённого верификатора зафиксирован на RSA и ECDSA с семейством SHA-2; SHA-1 и MD5 структурно исключены. Подписная арифметика выполняется во встроенной программной криптографии (phpseclib). NextPDF не заявляет о валидации по FIPS 140-3 для этой арифметики. Профиль криптополитики Enterprise FIPS 140-3 задокументирован вместе с модулем безопасности; он ограничивает выбор алгоритмов и не меняет ни структуры доверенных списков, ни поведение этого модуля с отказом в закрытое состояние.

УтверждениеСтандартПункт
Доверенный список, у которого Next update прошёл, отбрасывается как просроченный.ETSI TS 119 612§5.3.15
Поля даты-времени — это строки ISO 8601 в UTC с обозначением Z.ETSI TS 119 612§5.1.3
Оператор схемы подписывает доверенный список ради подлинности и целостности.ETSI TS 119 612§5.7.1
Статус квалифицированной службы — это URI статуса granted или withdrawn.ETSI TS 119 612§5.5.4
Квалифицированный УЦ идентифицируется по URI типа службы Svctype/CA/QC.ETSI TS 119 612§5.5.1.1
Порядковый номер TSL начинается с 1 и увеличивается при каждом релизе.ETSI TS 119 612§5.3.2

Все пункты пересказаны; NextPDF не воспроизводит нормативный текст. NextPDF не заявляет о соответствии ETSI TS 119 612 и не заявляет о сертификации eIDAS. Потребление доверенного списка не делает подпись, сертификат или вывод NextPDF «квалифицированным»; квалификация принадлежит поставщику услуг доверия под надзором государства-члена, а юридическая сила лежит вне этого модуля. Ограничения модели обработки XMLDSig (трансформация вложенной подписи, исключительная канонизация, ссылка, покрывающая корень) задокументированы из профиля проверки продукта; спецификация W3C XML Signature находится вне цитируемого набора доказательств. Этот модуль решает только то, приемлем ли список как входные данные доверия; проверка пути сертификата относительно полученных якорей принадлежит слою валидации сертификатов.

  • Зависимости — интерфейсы PSR: клиент PSR-18, фабрика запросов PSR-17 и необязательный кэш PSR-16. Внедряйте в тестах in-memory-двойники; ни один этап не требует живого сетевого доступа, кроме холодного fetch().
  • Закрепляйте верхний якорь внеполосно. Для списков государств-членов якорь LOTL авторизует подписантов списков; верификатор никогда не начинает доверие из содержимого KeyInfo.
  • Фоновый опрос, обработка pivot-LOTL и взаимный TLS или аутентификация прокси находятся вне области действия загрузчика в этой версии. Планируйте обновление внешне и заново загружайте перед каждым nextUpdate.
  • Передавайте в buildBundle() момент валидации, а не момент построения. Пересобирайте набор после каждого обновления; никогда не кэшируйте набор дольше nextUpdate исходного списка.
  • bundleVersion имеет наблюдаемую форму tsl-<territory>-seq<sequenceNumber>; rawXmlSha256 на TslDocument поддерживает записи доказательств и обнаружение повторов.
  • Некорректные записи служб разбираются с защитными значениями-заглушками; некорректная цифровая идентичность, дошедшая до построения набора, отказывает в закрытое состояние с InvalidArgumentException.
  • Классы несут аннотации исходника пакета @since 1.10.0 (TslFetchException: 3.2.0). TslDocument, TspService и TspServiceQualifier помечены в исходнике @api.

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