Aller au contenu
getnextpdf.com

Enterprise édition

Listes de confiance — Référence approfondie

Cette page est la référence approfondie de la surface des listes de confiance dans NextPDF Enterprise. Cette surface, ce sont les douze classes publiques de l’espace de noms NextPDF\Enterprise\Security\Tsl. NextPDF\Enterprise\Security\Tsl\TslPolicyEnforcer est le point d’entrée orchestré : il ne renvoie un TslDocument que lorsque la récupération HTTP, la vérification XMLDSig, l’analyse structurelle et la barrière de péremption nextUpdate réussissent toutes. TslTrustAnchorProvider::buildBundle() dérive ensuite un paquet d’ancres de confiance à partir des services CA/QC actifs, en réaffirmant la fraîcheur à un instant fourni par l’appelant avant toute extraction d’ancre. Chaque échec lève une exception typée ; aucune étape ne se dégrade silencieusement. Le pipeline prend en charge la vérification des listes de confiance des États membres de l’UE et des ancres de confiance issues d’une LOTL (List of Trusted Lists) lorsqu’elles sont fournies par l’appelant ; la découverte automatique de la LOTL, l’interrogation périodique et le traitement des pivots sont hors périmètre.

Cette capacité est livrée dans NextPDF Enterprise (nextpdf/enterprise) et s’active avec une enveloppe de licence de palier Enterprise. Un déploiement dépourvu de ce droit ne charge pas les classes de la capacité. Comparer les éditions et obtenir une licence.

SymboleParamètresComportement par défautRenvoieLève ou échoue avecNotes
TslPolicyEnforcerTslFetcher $fetcher, TslSignatureVerifier $verifier, TslXmlParser $parserCombine récupération, vérification de signature, analyse et barrière de péremption en un seul point d’entréePropage les exceptions du pipeline ci-dessousfinal ; en échec fermé par construction
TslPolicyEnforcer::fetchAndVerifystring $urlRécupère une TSL, puis exécute verifyXml() sur les octetsTslDocumentTslFetchException, NetworkPolicyViolation, TslSignatureException, TslParseExceptionNe renvoie que lorsque les quatre étapes réussissent
TslPolicyEnforcer::verifyXmlstring $xmlVérifie la signature, analyse et rejette une liste périméeTslDocumentTslSignatureException, TslParseExceptionLa péremption est évaluée par rapport à l’heure système actuelle
TslFetcherClientInterface $httpClient, RequestFactoryInterface $requestFactory, ?CacheInterface $cache = null, int $defaultTtlSeconds = 3600, int $maxBytes = 16_777_216, NetworkPolicy $networkPolicy = NetworkPolicy::ONLINERécupération TSL/LOTL en HTTPS uniquement avec cache basé sur ETagfinal ; la garde SSRF bloque les hôtes privés, de bouclage, lien-local et de métadonnées, avec atténuation du DNS-rebinding
TslFetcher::fetchstring $urlGET avec revalidation If-None-Match ; met en cache le corps et l’ETag sous le TTL configuréstring (octets XML bruts)TslFetchException, NetworkPolicyViolationLit au plus $maxBytes octets ; sous STRICT_OFFLINE, seul un corps en cache est servi
TslSignatureVerifierarray $trustAnchorsPem, int $clockTolerance = 0Vérificateur XMLDSig épinglé aux ancres de confiance configuréesInvalidArgumentException lorsque la liste d’ancres est videfinal ; listes d’autorisation dans ALLOWED_SIG_ALG et ALLOWED_DIGEST_ALG
TslSignatureVerifier::verifystring $xmlVérifie la signature XMLDSig enveloppée en échec ferméstring (PEM du certificat signataire)TslSignatureException avec un code de raison lisible par machineLes certificats de KeyInfo ne sont jamais dignes de confiance à eux seuls ; le signataire doit chaîner jusqu’à une ancre configurée
TslXmlParser::parsestring $xmlAnalyse structurelle en un TslDocument ; indifférent à la signatureTslDocumentTslParseExceptionRejette tout DOCTYPE en échec fermé avant l’analyse ; charge avec LIBXML_NONET ; les appelants doivent vérifier avant de faire confiance au résultat
TslTrustAnchorProvider::buildBundleTslDocument $tsl, DateTimeImmutable $nowAffirme d’abord la fraîcheur, puis collecte les certificats des services CA/QC actifsEnterpriseCaTrustAnchorBundleTslParseExceptionLa barrière de fraîcheur précède toute extraction d’ancre ; un ensemble de résultats vide lève une exception
TslDocumentHuit propriétés readonly promues (voir le bloc du constructeur)Objet-valeur immuable de la TSL analyséefinal readonly ; annoté @api dans la source
TslDocument::isStaleDateTimeImmutable $nowCompare nextUpdate à $now après une analyse UTC en échec ferméboolTslParseExceptionRequiert un désignateur Z explicite ou un décalage numérique
TslDocument::assertFreshDateTimeImmutable $nowLève une exception lorsque la liste est périmée ou que nextUpdate est inanalysablevoidTslParseExceptionLa barrière de fraîcheur à la frontière du consommateur
TslDocument::servicesOfTypestring $serviceTypeIdentifierFiltre les services par URI de type de service ETSIlist<TspService>Ne lève pas
TslDocument::activeServicesRenvoie uniquement les services en statut « granted »list<TspService>Ne lève pas« Granted » signifie TspService::STATUS_GRANTED
TspServiceHuit propriétés readonly promuesUne entrée de service de confiance dans une TSLfinal readonly ; constantes pour le statut et les URI de type de service
TspService::isGrantedÉgalité de statut avec l’URI « granted »boolNe lève pas
TspService::isQualifiedCaÉgalité de type avec l’URI CA/QCboolNe lève pas
TspServiceQualifierstring $qualifierUri, string $criteriaListAssert = 'all', array $policyOidConditions = [], array $keyUsageConditions = []Un qualificateur de service ETSI avec critères optionnelsfinal readonly ; constantes FOR_ESIG, FOR_ESEAL, FOR_WSA, QSCD_STATEMENT, NO_QSCD
EnterpriseCaTrustAnchorBundlearray $anchorsPem, string $bundleVersion, string $bundleSha256Paquet à ancres épinglées ; valide le condensé fourni par rapport aux ancres fournies à la constructionInvalidArgumentExceptionÀ obtenir via buildBundle() ; ne pas construire à la main ; implémente TrustAnchorStoreInterface
EnterpriseCaTrustAnchorBundle::containsFingerprintstring $anchorDerSha256HexAppartenance d’une ancre par SHA-256 hexadécimal sur le corps DERboolNe lève pas
EnterpriseCaTrustAnchorBundle::computeBundleSha256array $anchorsPemSHA-256 canonique sur la concaténation PEM normalisée en sauts de lignestringNe lève passtatic
TslFetchExceptionSignale l’échec d’une récupération de TSLfinal ; étend RuntimeException
TslParseExceptionSignale un échec structurel ou de fraîcheurfinal ; étend RuntimeException
TslSignatureExceptionstring $reason, string $messageSignale un échec de vérification XMLDSig avec un code de raisonfinal ; $reason readonly public (voir les codes de raison ci-dessous)

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)

Codes de raison de TslSignatureException : missing_signature, untrusted_signer, invalid_signature, digest_mismatch, unsupported_algorithm, unsupported_transform, expired_anchor.

  • L’ordre du pipeline est fixe : récupération, vérification XMLDSig, analyse structurelle, barrière de péremption. TslPolicyEnforcer ne renvoie un TslDocument que lorsque les quatre réussissent. Une liste de confiance est signée par son opérateur de schéma afin que les parties utilisatrices puissent en vérifier l’authenticité et l’intégrité — ETSI TS 119 612 §5.7.1.
  • TslXmlParser est indifférent à la signature par conception. Les appelants doivent vérifier la signature avant de faire confiance à un quelconque champ analysé. TslPolicyEnforcer::verifyXml() impose cet ordre.
  • L’invariant de fraîcheur est imposé à chaque frontière de consommateur. Une liste dont le nextUpdate est dépassé est expirée et refusée — ETSI TS 119 612 §5.3.15. verifyXml() filtre par rapport à l’heure système actuelle ; TslDocument::assertFresh() et buildBundle() filtrent par rapport à un instant fourni par l’appelant.
  • L’analyse de fraîcheur est en échec fermé. Les champs date-heure sont des valeurs ISO 8601 UTC avec un désignateur explicite — ETSI TS 119 612 §5.1.3. Un nextUpdate sans Z explicite ni décalage numérique lève TslParseException ; la valeur n’est jamais réinterprétée dans le fuseau horaire local du serveur.
  • buildBundle() appelle assertFresh($now) avant d’extraire toute ancre, puis n’admet que les services à la fois « granted » et CA/QC. « Granted » et « withdrawn » sont les URI de statut des services qualifiés — ETSI TS 119 612 §5.5.4. CA/QC est l’URI de type de service de l’AC qualifiée — ETSI TS 119 612 §5.5.1.1.
  • La version du paquet est dérivée du territoire du schéma et du numéro de séquence de la TSL. Le numéro de séquence est monotone d’une publication à l’autre — ETSI TS 119 612 §5.3.2. Le condensé du paquet est un SHA-256 canonique sur les PEM des ancres, et containsFingerprint() répond à l’appartenance par SHA-256 du DER.
  • Le vérificateur ne fait confiance qu’aux ancres configurées. Les certificats trouvés dans KeyInfo servent de feuille signataire et d’intermédiaires candidats ; la chaîne doit atteindre une ancre configurée en une profondeur maximale de 8, chaque maillon doit être temporellement valide, et un certificat émetteur doit porter basicConstraints cA=TRUE (plus keyCertSign lorsque keyUsage est présent).
  • Le profil de vérification est une liste d’autorisation : RSA ou ECDSA avec SHA-256, SHA-384 ou SHA-512 ; méthodes de condensé SHA-256, SHA-384 ou SHA-512 ; canonicalisation exclusive uniquement ; et exactement la paire de transformations « signature enveloppée » plus C14N exclusive sur la ds:Reference couvrant la liste. Tout le reste échoue avec unsupported_algorithm ou unsupported_transform.
  • TslFetcher refuse les URL non-HTTPS et applique une garde SSRF avant toute sortie. Sous NetworkPolicy::STRICT_OFFLINE, il sert un corps précédemment mis en cache ou lève NetworkPolicyViolation ; aucune requête sortante n’est jamais émise.
  • Liste périmée. Une TslParseException issue de verifyXml(), assertFresh() ou buildBundle() signifie que la source de confiance est inutilisable. Traite-la comme un échec de rafraîchissement opérationnel, pas comme un verdict de signature.
  • nextUpdate non canonique. Une valeur sans Z explicite ni décalage numérique lève une exception au lieu d’être analysée de manière laxiste. ETSI TS 119 612 §5.1.3 impose la forme UTC Z ; la barrière accepte aussi un décalage numérique explicite et rejette tout le reste.
  • Dérive au moment de l’utilisation. verifyXml() filtre au moment de la vérification ; un document conservé en mémoire au-delà de son nextUpdate échoue toujours à la barrière ultérieure buildBundle($tsl, $now).
  • Configuration d’ancres vide. TslSignatureVerifier refuse la construction avec une liste d’ancres vide (InvalidArgumentException).
  • Aucun service utilisable. Une liste fraîche sans service CA/QC « granted » lève TslParseException depuis buildBundle() ; un paquet vide n’est jamais produit.
  • Posture hors ligne. STRICT_OFFLINE sans corps en cache lève NetworkPolicyViolation. La recherche dans le cache précède la vérification de la politique, si bien qu’une liste en cache maintient la validation en environnement isolé opérationnelle.
  • Réponse surdimensionnée ou vide. fetch() lit au plus $maxBytes octets (16 Mio par défaut) ; une liste tronquée échoue ensuite à la vérification du condensé en aval. Un corps vide lève TslFetchException.
  • DOCTYPE dans le XML. Tout DOCTYPE est rejeté avant que libxml ne construise une table d’entités, et de nouveau après le chargement. Cela ferme les classes d’entrée XXE et d’expansion d’entités (billion-laughs).
  • Signatures multiples. Seule la ds:Signature enveloppée vérifiée est retirée avant le calcul du condensé ; les signatures voisines et les contre-signatures sont préservées. Des références XAdES supplémentaires sont autorisées, mais exactement une ds:Reference doit couvrir la racine du document.
  • Matériel de chaîne expiré. Un signataire, un intermédiaire ou une ancre expiré ou pas encore valide échoue avec la raison expired_anchor. clockTolerance élargit symétriquement la fenêtre d’acceptation et vaut 0 par défaut.

La liste d’autorisation du vérificateur est fixée à RSA et ECDSA avec la famille SHA-2 ; SHA-1 et MD5 sont structurellement exclus. L’arithmétique de signature s’exécute dans la cryptographie logicielle embarquée (phpseclib). NextPDF ne formule aucune revendication de validation FIPS 140-3 pour cette arithmétique. Le profil de politique cryptographique FIPS 140-3 d’Enterprise est documenté avec le module de sécurité ; il contraint la sélection d’algorithmes et ne modifie ni les structures des listes de confiance ni le comportement en échec fermé de ce module.

RevendicationNormeClause
Une liste de confiance dont la « Next update » est dépassée est écartée comme expirée.ETSI TS 119 612§5.3.15
Les champs date-heure sont des chaînes ISO 8601 en UTC avec le désignateur Z.ETSI TS 119 612§5.1.3
L’opérateur de schéma signe la liste de confiance pour l’authenticité et l’intégrité.ETSI TS 119 612§5.7.1
Le statut d’un service qualifié est l’URI de statut « granted » ou « withdrawn ».ETSI TS 119 612§5.5.4
Une AC qualifiée est identifiée par l’URI de type de service Svctype/CA/QC.ETSI TS 119 612§5.5.1.1
Le numéro de séquence de la TSL commence à 1 et s’incrémente à chaque publication.ETSI TS 119 612§5.3.2

Toutes les clauses sont paraphrasées ; NextPDF ne reproduit pas le texte normatif. NextPDF ne formule aucune revendication de conformité ETSI TS 119 612 ni aucune revendication de certification eIDAS. Consommer une liste de confiance ne rend « qualifiés » ni une signature, ni un certificat, ni une sortie NextPDF ; la qualification relève du prestataire de services de confiance sous la supervision d’un État membre, et l’effet juridique est en dehors de ce module. Les contraintes du modèle de traitement XMLDSig (transformation « signature enveloppée », canonicalisation exclusive, référence couvrant la racine) sont documentées à partir du profil de vérification du produit ; la spécification W3C XML Signature est en dehors de l’ensemble de preuves cité. Ce module décide seulement si une liste est acceptable comme entrée de confiance ; la validation de chemin de certification par rapport aux ancres résultantes relève de la couche de validation des certificats.

  • Les dépendances sont des interfaces PSR : un client PSR-18, une fabrique de requêtes PSR-17 et un cache PSR-16 optionnel. Injecte des doublures en mémoire dans les tests ; aucune étape n’exige un accès réseau réel, hormis un fetch() à froid.
  • Épingle l’ancre supérieure hors bande. Pour les listes des États membres, l’ancre LOTL autorise les signataires de listes ; le vérificateur n’amorce jamais la confiance depuis le contenu de KeyInfo.
  • L’interrogation périodique en arrière-plan, le traitement des LOTL pivots et l’authentification par TLS mutuel ou par proxy sont hors du périmètre du récupérateur dans cette version. Planifie le rafraîchissement en externe et re-récupère avant chaque nextUpdate.
  • Passe l’instant de validation, pas l’instant de construction, à buildBundle(). Reconstruis le paquet après chaque rafraîchissement ; ne mets jamais un paquet en cache au-delà du nextUpdate de la liste source.
  • bundleVersion a la forme observable tsl-<territory>-seq<sequenceNumber> ; rawXmlSha256 sur TslDocument prend en charge les enregistrements de preuve et la détection de rejeu.
  • Les entrées de service malformées sont analysées avec des valeurs de remplacement défensives ; une identité numérique malformée qui atteint la construction du paquet échoue en fermé avec InvalidArgumentException.
  • Les classes portent des annotations source de paquet @since 1.10.0 (TslFetchException : 3.2.0). TslDocument, TspService et TspServiceQualifier sont annotés @api dans la source.

Cette page ne documente que le comportement observable de l’extérieur et la surface de l’API publique prise en charge. Les chemins d’espaces de noms internes, les classes auxiliaires, les tables de mécanismes, les noms de fichiers de runbook et les préfixes de tickets sont hors périmètre.