Pular para o conteúdo
getnextpdf.com

Enterprise edição

Listas confiáveis — Referência Profunda

Esta página é a referência aprofundada da superfície de listas confiáveis no NextPDF Enterprise. A superfície são as doze classes públicas do namespace NextPDF\Enterprise\Security\Tsl. NextPDF\Enterprise\Security\Tsl\TslPolicyEnforcer é o ponto de entrada orquestrado: ele retorna um TslDocument somente quando o fetch HTTP, a verificação XMLDSig, o parse estrutural e o portão de obsolescência nextUpdate passam, todos. TslTrustAnchorProvider::buildBundle() então deriva um pacote de âncoras de confiança a partir dos serviços CA/QC ativos, reafirmando a atualidade em um instante fornecido pelo chamador antes que qualquer âncora seja extraída. Cada falha lança uma exceção tipada; nenhum estágio degrada silenciosamente. O pipeline oferece suporte à verificação de listas confiáveis de Estados-membros da UE e a âncoras de confiança originadas de LOTL (List of Trusted Lists) quando fornecidas pelo chamador; a descoberta automática de LOTL, o polling e o processamento de pivots estão fora do escopo.

Esta capacidade é entregue no NextPDF Enterprise (nextpdf/enterprise) e é ativada com um envelope de licença de nível Enterprise. Uma implantação sem essa habilitação não carrega as classes da capacidade. Compare as edições e obtenha uma licença.

SímboloParâmetrosComportamento padrãoRetornaLança ou falha comNotas
TslPolicyEnforcerTslFetcher $fetcher, TslSignatureVerifier $verifier, TslXmlParser $parserCombina fetch, verificação de assinatura, parse e portão de obsolescência em um único ponto de entradaPropaga as exceções de pipeline abaixofinal; fail-closed por construção
TslPolicyEnforcer::fetchAndVerifystring $urlFaz o fetch de uma TSL e então executa verifyXml() sobre os bytesTslDocumentTslFetchException, NetworkPolicyViolation, TslSignatureException, TslParseExceptionRetorna somente quando os quatro estágios passam
TslPolicyEnforcer::verifyXmlstring $xmlVerifica a assinatura, faz o parse e rejeita uma lista obsoletaTslDocumentTslSignatureException, TslParseExceptionA obsolescência é avaliada contra a hora atual do sistema
TslFetcherClientInterface $httpClient, RequestFactoryInterface $requestFactory, ?CacheInterface $cache = null, int $defaultTtlSeconds = 3600, int $maxBytes = 16_777_216, NetworkPolicy $networkPolicy = NetworkPolicy::ONLINERecuperação de TSL/LOTL somente por HTTPS com cache baseado em ETagfinal; a proteção contra SSRF bloqueia hosts privados, de loopback, link-local e de metadados com mitigação de DNS-rebinding
TslFetcher::fetchstring $urlGET com revalidação If-None-Match; faz cache do corpo mais o ETag sob o TTL configuradostring (bytes XML brutos)TslFetchException, NetworkPolicyViolationLê no máximo $maxBytes bytes; sob STRICT_OFFLINE apenas um corpo em cache é servido
TslSignatureVerifierarray $trustAnchorsPem, int $clockTolerance = 0Verificador XMLDSig fixado às âncoras de confiança configuradasInvalidArgumentException quando a lista de âncoras está vaziafinal; allowlists em ALLOWED_SIG_ALG e ALLOWED_DIGEST_ALG
TslSignatureVerifier::verifystring $xmlVerifica a assinatura XMLDSig envelopada de forma fail-closedstring (PEM do certificado do assinante)TslSignatureException com um código de motivo legível por máquinaCertificados em KeyInfo nunca são confiáveis por si só; o assinante deve encadear até uma âncora configurada
TslXmlParser::parsestring $xmlParse estrutural em um TslDocument; agnóstico à assinaturaTslDocumentTslParseExceptionRejeita qualquer DOCTYPE de forma fail-closed antes do parse; carrega com LIBXML_NONET; os chamadores devem verificar antes de confiar no resultado
TslTrustAnchorProvider::buildBundleTslDocument $tsl, DateTimeImmutable $nowAfirma a atualidade primeiro e então coleta os certificados dos serviços CA/QC ativosEnterpriseCaTrustAnchorBundleTslParseExceptionO portão de atualidade precede qualquer extração de âncora; um conjunto de resultados vazio lança exceção
TslDocumentOito propriedades readonly promovidas (veja a cerca do construtor)Objeto de valor imutável da TSL parseadafinal readonly; anotado na fonte com @api
TslDocument::isStaleDateTimeImmutable $nowCompara nextUpdate contra $now após um parse UTC fail-closedboolTslParseExceptionExige um designador Z explícito ou de offset numérico
TslDocument::assertFreshDateTimeImmutable $nowLança exceção quando a lista está obsoleta ou nextUpdate é imparseávelvoidTslParseExceptionO portão de atualidade na fronteira do consumidor
TslDocument::servicesOfTypestring $serviceTypeIdentifierFiltra serviços pela URI de tipo de serviço da ETSIlist<TspService>Não lança exceção
TslDocument::activeServicesRetorna serviços apenas no status grantedlist<TspService>Não lança exceçãoGranted significa TspService::STATUS_GRANTED
TspServiceOito propriedades readonly promovidasUma entrada de serviço de confiança dentro de uma TSLfinal readonly; constantes para status e URIs de tipo de serviço
TspService::isGrantedIgualdade de status contra a URI grantedboolNão lança exceção
TspService::isQualifiedCaIgualdade de tipo contra a URI CA/QCboolNão lança exceção
TspServiceQualifierstring $qualifierUri, string $criteriaListAssert = 'all', array $policyOidConditions = [], array $keyUsageConditions = []Um qualificador de serviço da ETSI com critérios opcionaisfinal readonly; constantes FOR_ESIG, FOR_ESEAL, FOR_WSA, QSCD_STATEMENT, NO_QSCD
EnterpriseCaTrustAnchorBundlearray $anchorsPem, string $bundleVersion, string $bundleSha256Pacote de âncoras fixadas; valida o digest fornecido contra as âncoras fornecidas na construçãoInvalidArgumentExceptionObtenha de buildBundle(); não construa à mão; implementa TrustAnchorStoreInterface
EnterpriseCaTrustAnchorBundle::containsFingerprintstring $anchorDerSha256HexPertencimento de âncora por SHA-256 em hex sobre o corpo DERboolNão lança exceção
EnterpriseCaTrustAnchorBundle::computeBundleSha256array $anchorsPemSHA-256 canônico sobre a concatenação de PEM normalizada por quebras de linhastringNão lança exceçãostatic
TslFetchExceptionSinaliza uma recuperação de TSL falhafinal; estende RuntimeException
TslParseExceptionSinaliza uma falha estrutural ou de atualidadefinal; estende RuntimeException
TslSignatureExceptionstring $reason, string $messageSinaliza uma falha de verificação XMLDSig com um código de motivofinal; readonly público $reason (veja os códigos de motivo abaixo)

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)

Códigos de motivo de TslSignatureException: missing_signature, untrusted_signer, invalid_signature, digest_mismatch, unsupported_algorithm, unsupported_transform, expired_anchor.

  • A ordem do pipeline é fixa: fetch, verificação XMLDSig, parse estrutural, portão de obsolescência. TslPolicyEnforcer retorna um TslDocument somente quando os quatro têm sucesso. Uma lista confiável é assinada pelo seu operador de esquema para que as partes confiantes possam checar autenticidade e integridade — ETSI TS 119 612 §5.7.1.
  • TslXmlParser é agnóstico à assinatura por design. Os chamadores devem verificar a assinatura antes de confiar em qualquer campo parseado. TslPolicyEnforcer::verifyXml() impõe essa ordenação.
  • A invariante de atualidade é imposta em cada fronteira de consumidor. Uma lista cujo nextUpdate já passou está expirada e é recusada — ETSI TS 119 612 §5.3.15. verifyXml() compara com a hora atual do sistema; TslDocument::assertFresh() e buildBundle() comparam com um instante fornecido pelo chamador.
  • O parse de atualidade é fail-closed. Os campos de data-hora são valores ISO 8601 em UTC com um designador explícito — ETSI TS 119 612 §5.1.3. Um nextUpdate sem um Z explícito ou offset numérico lança TslParseException; o valor nunca é reinterpretado no fuso horário local do servidor.
  • buildBundle() chama assertFresh($now) antes de extrair qualquer âncora e então admite apenas serviços que sejam ao mesmo tempo granted e CA/QC. Granted e withdrawn são as URIs de status de serviço qualificado — ETSI TS 119 612 §5.5.4. CA/QC é a URI de tipo de serviço de CA qualificada — ETSI TS 119 612 §5.5.1.1.
  • A versão do pacote é derivada do território do esquema e do número de sequência da TSL. O número de sequência é monotônico entre releases — ETSI TS 119 612 §5.3.2. O digest do pacote é um SHA-256 canônico sobre os PEMs das âncoras, e containsFingerprint() responde ao pertencimento por SHA-256 do DER.
  • O verificador confia apenas nas âncoras configuradas. Certificados encontrados em KeyInfo servem como o leaf do assinante e intermediários candidatos; a cadeia deve alcançar uma âncora configurada dentro de profundidade 8, cada elo deve ser temporalmente válido, e um certificado emissor deve carregar basicConstraints cA=TRUE (mais keyCertSign quando keyUsage está presente).
  • O perfil de verificação é uma allowlist: RSA ou ECDSA com SHA-256, SHA-384 ou SHA-512; métodos de digest SHA-256, SHA-384 ou SHA-512; apenas canonicalização exclusiva; e exatamente o par de transforms enveloped-signature mais exclusive-C14N na ds:Reference que cobre a lista. Qualquer outra coisa falha com unsupported_algorithm ou unsupported_transform.
  • TslFetcher recusa URLs não-HTTPS e aplica uma proteção contra SSRF antes de qualquer egresso. Sob NetworkPolicy::STRICT_OFFLINE ele serve um corpo previamente cacheado ou lança NetworkPolicyViolation; nenhuma requisição de saída é jamais enviada.
  • Lista obsoleta. Uma TslParseException vinda de verifyXml(), assertFresh() ou buildBundle() significa que a fonte de confiança está inutilizável. Trate-a como uma falha operacional de atualização, não como um veredito de assinatura.
  • nextUpdate não canônico. Um valor sem um Z explícito ou offset numérico lança exceção em vez de fazer o parse de forma leniente. A ETSI TS 119 612 §5.1.3 exige a forma UTC Z; o portão também aceita um offset numérico explícito e rejeita todo o resto.
  • Deriva de tempo-de-uso. verifyXml() compara no momento da verificação; um documento mantido em memória além do nextUpdate ainda falha no portão posterior buildBundle($tsl, $now).
  • Configuração de âncoras vazia. TslSignatureVerifier recusa a construção com uma lista de âncoras vazia (InvalidArgumentException).
  • Nenhum serviço utilizável. Uma lista atual sem serviços CA/QC granted lança TslParseException a partir de buildBundle(); um pacote vazio nunca é produzido.
  • Postura offline. STRICT_OFFLINE sem corpo em cache lança NetworkPolicyViolation. A consulta ao cache precede a checagem de política, de modo que uma lista em cache mantém a validação em ambiente air-gapped funcionando.
  • Resposta grande demais ou vazia. fetch() lê no máximo $maxBytes bytes (padrão 16 MiB); uma lista truncada então falha na verificação de digest mais adiante. Um corpo vazio lança TslFetchException.
  • DOCTYPE no XML. Qualquer DOCTYPE é rejeitado antes de o libxml construir uma tabela de entidades, e novamente após o carregamento. Isso fecha as classes de entrada XXE e de expansão de entidades (billion-laughs).
  • Múltiplas assinaturas. Apenas a ds:Signature envelopada verificada é removida antes do cálculo do digest; assinaturas irmãs e contra-assinaturas são preservadas. Referências XAdES adicionais são permitidas, mas exatamente uma ds:Reference deve cobrir a raiz do documento.
  • Material de cadeia expirado. Um assinante, intermediário ou âncora expirado ou ainda-não-válido falha com o motivo expired_anchor. clockTolerance amplia a janela de aceitação simetricamente e assume o padrão 0.

A allowlist do verificador é fixada em RSA e ECDSA com a família SHA-2; SHA-1 e MD5 são estruturalmente excluídos. A aritmética de assinatura roda em criptografia de software agrupada (phpseclib). A NextPDF não faz nenhuma alegação de validação FIPS 140-3 para essa aritmética. O perfil de política de criptografia FIPS 140-3 do Enterprise é documentado junto ao módulo de segurança; ele restringe a seleção de algoritmos e não altera as estruturas de listas confiáveis nem o comportamento fail-closed deste módulo.

AlegaçãoNormaCláusula
Uma lista confiável cujo Next update já passou é descartada como expirada.ETSI TS 119 612§5.3.15
Os campos de data-hora são strings ISO 8601 em UTC com o designador Z.ETSI TS 119 612§5.1.3
O operador de esquema assina a lista confiável para autenticidade e integridade.ETSI TS 119 612§5.7.1
O status de serviço qualificado é a URI de status granted ou withdrawn.ETSI TS 119 612§5.5.4
Uma CA qualificada é identificada pela URI de tipo de serviço Svctype/CA/QC.ETSI TS 119 612§5.5.1.1
O número de sequência da TSL começa em 1 e incrementa a cada release.ETSI TS 119 612§5.3.2

Todas as cláusulas são parafraseadas; a NextPDF não reproduz texto normativo. A NextPDF não faz nenhuma alegação de conformidade com a ETSI TS 119 612 nem nenhuma alegação de certificação eIDAS. Consumir uma lista confiável não torna uma assinatura, um certificado ou uma saída da NextPDF “qualificada”; a qualificação pertence ao provedor de serviço de confiança sob supervisão do Estado-membro, e o efeito jurídico está fora deste módulo. As restrições do modelo de processamento XMLDSig (transform enveloped-signature, canonicalização exclusiva, referência que cobre a raiz) são documentadas a partir do perfil de verificação do produto; a especificação W3C XML Signature está fora do conjunto de evidências citado. Este módulo decide apenas se uma lista é aceitável como entrada de confiança; a validação de caminho de certificado contra as âncoras resultantes pertence à camada de validação de certificados.

  • As dependências são interfaces PSR: um cliente PSR-18, uma request factory PSR-17 e um cache PSR-16 opcional. Injete dublês em memória nos testes; nenhum estágio requer acesso à rede ao vivo, exceto um fetch() frio.
  • Fixe (pin) a âncora de topo fora de banda. Para listas de Estados-membros, a âncora LOTL autoriza os assinantes das listas; o verificador nunca inicializa a confiança a partir do conteúdo de KeyInfo.
  • Polling em segundo plano, processamento de pivot-LOTL e autenticação mutual-TLS ou por proxy estão fora do escopo do fetcher nesta versão. Agende a atualização externamente e refaça o fetch antes de cada nextUpdate.
  • Passe o instante de validação, não o instante de construção, para buildBundle(). Reconstrua o pacote após cada atualização; nunca faça cache de um pacote além do nextUpdate da lista de origem.
  • bundleVersion tem a forma observável tsl-<territory>-seq<sequenceNumber>; rawXmlSha256 em TslDocument dá suporte a registros de evidência e detecção de replay.
  • Entradas de serviço malformadas são parseadas com valores placeholder defensivos; uma identidade digital malformada que chegue à construção do pacote falha de forma fechada com InvalidArgumentException.
  • As classes carregam anotações de fonte de pacote @since 1.10.0 (TslFetchException: 3.2.0). TslDocument, TspService e TspServiceQualifier são anotados na fonte com @api.

Esta página documenta apenas o comportamento externamente observável e a superfície pública de API suportada. Caminhos de namespace internos, classes auxiliares, tabelas de mecanismos, nomes de arquivos de runbook e prefixos de ticket estão fora do escopo.