Aller au contenu
getnextpdf.com

Enterprise édition

Vérification de signature — Référence détaillée

Cette page est la référence détaillée de la surface de vérification AdES dans NextPDF Enterprise. Le point d’entrée est NextPDF\Enterprise\Security\Validation\AdESValidationEngine. Elle implémente les flux de validation modélisés sur ETSI de NextPDF pour les contrôles d’horodatage basique, avec temps, long terme et archivage : validation basique, validation avec temps, validation avec données à long terme, et validation de la chaîne de couverture DocTimeStamp d’archivage. Les résultats sont des valeurs ValidationReport portant des cas d’énumération MainIndication et SubIndication avec des valeurs de chaîne URN ETSI. Surfaces annexes documentées ici : le SPI SignatureDataExtractor et son implémentation CmsSignatureDataExtractor, le scanner au niveau octet PdfSignatureDictionaryScanner, la surface de validation de chemin NextPDF\Enterprise\Security\Pki, et BatchSignatureValidator. Pour des conseils au niveau du flux de travail, voir Vérification de signature : côté vérification cryptographique AdES / PAdES.

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

SymboleParamètresComportement par défautRetourneLève ou échoue avecNotes
AdESValidationEngine::__construct11 paramètres optionnels : ?PathValidatorInterface $chainValidator, ?SignatureDataExtractor $extractor, ClockInterface $clock, ?LoggerInterface $logger, string $defaultPolicy, NetworkPolicy $networkPolicy, et cinq collaborateurs de vérification optionnelsTous les défauts sont en échec fermé : validateur de chemin Pki sur l’horloge du moteur, pas d’extracteur, pas de magasin de confiance TSANouveau moteurNe lève pasSans magasin de confiance, l’évaluation de la chaîne TSA renvoie « non fiable » ; cela correspond à INDETERMINATE, jamais à un succès
AdESValidationEngine::validateBasicstring $signedData, string $signatureValidation basique : format, empreinte, crypto, algorithme faible, chaîne, révocation contrôlée par provenanceValidationReportNe lève pas ; les échecs d’extraction et de chemin correspondent à des rapports en échec ferméSans extracteur, contrôles de garde uniquement ; voir les cas limites
AdESValidationEngine::validateWithTimestring $signedData, string $signature, DateTimeImmutable $claimedTimeValidation basique d’abord ; fenêtre de certificat et révocation comparées au temps revendiquéValidationReportNe lève pasContrôle strict de l’horodatage de signature lorsque l’attribut est présent ; $claimedTime reste l’ancre temporelle
AdESValidationEngine::validateWithLongTermDatastring $signedData, string $signature, array $dssData (certs/ocsps/crls)Succès basique requis ; contrôle d’horodatage de signature armé avec TSA-at-genTime ; contrôles POE, révocation DSS et archivageValidationReportNe lève pasNetworkPolicy::STRICT_OFFLINE avec des données embarquées insuffisantes produit INDETERMINATE / TRY_LATER
AdESValidationEngine::validateArchivalTimestampChainstring $pdfBytes, array $dssData = [], ?TrustAnchorStoreInterface $anchors = nullChaîne de couverture DocTimeStamp fondée sur des preuves sur les octets exacts du ByteRangeValidationReportNe lève pas sur des octets hostilesTOTAL_PASSED uniquement pour une chaîne fiable couvrant jusqu’à l’EOF
MainIndicationÉnumération à valeurs de chaîne, trois casValeurs URN ETSI ; voir la liste des cas ci-dessous
SubIndicationÉnumération à valeurs de chaîne, quinze casValeurs URN ETSI ; voir la liste des cas ci-dessous
ValidationReport::__constructMainIndication $mainIndication, ?SubIndication $subIndication, DiagnosticData $diagnosticData, DateTimeImmutable $validationTime, string $validationPolicy = ''Résultat de validation immuable (final readonly)Nouveau rapportNe lève pasisPassed(), isFailed(), isIndeterminate(), toArray()
DiagnosticData::__constructarray $certificateChain, array $timestamps, array $revocationData, string $validationPolicy, string $signatureFormat, array $warnings (tous avec valeur par défaut)Conteneur de preuves immuable ; piste d’audit uniquementNouvelle valeurNe lève pastoArray() sérialise des références pour le reporting
SignatureDataExtractor::extractstring $signedData, string $signatureSPI : analyser le CMS et extraire les composants de validationExtractedSignatureDataSignatureExtractionException lorsque la signature ne peut pas être analyséeInterface ; découple l’analyse ASN.1 du moteur
CmsSignatureDataExtractor::extractstring $signedData, string $signatureExtraire puis vérifier cryptographiquement une signature basique PAdES détachéeExtractedSignatureDataSignatureExtractionException uniquement lorsque le CMS ne peut pas du tout être analyséUn échec cryptographique ou de liaison renvoie des données avec cryptoValid / hashValid à faux ; il ne lève jamais pour cela
PdfSignatureDictionaryScanner::scanstring $pdfBytesAnalyse au niveau octet des dictionnaires /ByteRange + /Contents avec des recoupements anti-usurpation à ajustement précislist<PdfSignatureOccurrence>Total ; ne lève jamais ; les candidats malformés sont ignorésOrdonné par fin de couverture, du plus précoce au plus tardif
PathValidatorInterface::validatearray $chain, ?DateTimeImmutable $validationTime = null, array $initialPolicies = []Validation de chemin RFC 5280 §6.1.4 avec traitement des politiquesPathValidationResultPathValidationException sur une chaîne structurellement invalide ou une limite adverse franchieLa chaîne va de l’entité finale d’abord à l’ancre en dernier
PathValidatorInterface::validateWithAiaChasingarray $chain, ?DateTimeImmutable $validationTime = nullRésolution AIA des intermédiaires manquants, puis validationPathValidationResultPathValidationExceptionLes récupérations sont plafonnées par un délai d’expiration et des limites d’octets
CertificateChainValidatorConstructeur : moteur, PathValidationOptions, horloge, logger ; withDefaults() statiqueL’implémentation du SPI avec les plafonds adverses par défautPathValidationResult depuis les deux méthodesPathValidationExceptionÉgalement levée lorsqu’un OpenSSLCertificate ne peut pas être exporté en PEM
PathValidationOptions::__constructPlafonds (maxDepth, maxPolicyFanout, fetchTimeoutSeconds, fetchSizeCapBytes) plus des drapeaux de politique, ?TrustAnchorStoreInterface $trustAnchors, bool $requireTrustedAnchorProfondeur 32, fan-out 64, 5 s par récupération, 10 Mio par récupération ; tous les drapeaux à fauxNouvelles optionsNe lève pasFabriques : defaults(), strict(), withTrustAnchors()
PathValidationResult::__constructbool $valid, string $trustAnchorFingerprint, DateTimeImmutable $validatedAt, array $validPolicies, ?RevocationCheckResult $revocation, bool $trustAnchorTrusted, array $fetchedCertificates, array $failureReasonsRésultat immuable ; trustAnchorTrusted par défaut à faux (échec fermé)Nouvelle valeurNe lève pasL’appartenance à la confiance est distincte de la validité structurelle
PolicyProcessorConstructeur : PolicyTreeState $state, PathValidationOptions $options ; processCertificate(string $certDer, int $depth, bool $selfIssued), finalizeWrapUp(), tree()Expansion, mappage et finalisation de l’arbre de politiques RFC 5280 §6.1.4void / list<non-empty-string> / PolicyTreePathValidationException sur tout échec de traitement de politique (échec fermé)La finalisation renvoie les OID de politique survivants, hors anyPolicy
PolicyTreeattach(PolicyTreeNode $node, PathValidationOptions $options), enforceFanout(...), remove(...), plus des requêtes de lectureL’état valid_policy_tree avec un index de profondeurVarie selon la méthodePathValidationException lorsque le nombre de feuilles vivantes dépasse le plafond de fan-outExpose ANY_POLICY_OID (2.5.29.32.0)
NameConstraintsChecker::processCertificatestring $certDer, bool $applyNameCheckAccumule et applique les sous-arbres autorisés / exclus selon RFC 5280 §6.1.4(g)voidPathValidationException sur un sous-arbre enfreint, une forme GeneralName non prise en charge dans une contrainte, ou un plafond franchiLes noms non comparables sont traités en échec fermé
TrustAnchorStoreInterface::containsFingerprintstring $anchorDerSha256HexAppartenance par SHA-256 en hexadécimal minuscule sur le certificat DER de l’ancreboolNe lève pasLe joint de confiance consulté par le validateur de chemin
BatchSignatureValidator::validatearray $inputs (list<DocumentSignatureInput>)Validation de signature multi-documents avec mise en cache de révocation par lotBatchValidationReportInvalidArgumentException sur une liste vide ; une garde de ressource rejette les lots au-delà de 1000 documentsRéside dans NextPDF\Enterprise\Signature
final class AdESValidationEngine
public function validateBasic(string $signedData, string $signature): ValidationReport
public function validateWithTime(
string $signedData,
string $signature,
DateTimeImmutable $claimedTime,
): ValidationReport
public function validateWithLongTermData(
string $signedData,
string $signature,
array $dssData,
): ValidationReport
public function validateArchivalTimestampChain(
string $pdfBytes,
array $dssData = [],
?TrustAnchorStoreInterface $anchors = null,
): ValidationReport
public function validate(
array $chain,
?DateTimeImmutable $validationTime = null,
array $initialPolicies = [],
): PathValidationResult;
public function validateWithAiaChasing(
array $chain,
?DateTimeImmutable $validationTime = null,
): PathValidationResult;
public static function withDefaults(
?ClockInterface $clock = null,
?AiaChaser $aiaChaser = null,
?LoggerInterface $logger = null,
): self
public function containsFingerprint(string $anchorDerSha256Hex): bool;
public function extract(string $signedData, string $signature): ExtractedSignatureData;
public function scan(string $pdfBytes): array
public function validate(array $inputs): BatchValidationReport

Énumérations d’indication. Cas de MainIndication : TOTAL_PASSED, TOTAL_FAILED, INDETERMINATE. Les valeurs sous-jacentes suivent le motif urn:etsi:019102:mainindication:total-passed (minuscules, avec traits d’union). Cas de SubIndication : HASH_FAILURE, SIG_CRYPTO_FAILURE, REVOKED, EXPIRED, NOT_YET_VALID, NO_POE, TRY_LATER, CERTIFICATE_CHAIN_GENERAL_FAILURE, FORMAT_FAILURE, REVOKED_CA_NO_POE, CRYPTO_CONSTRAINTS_FAILURE, POLICY_PROCESSING_FAILURE, REVOCATION_OUT_OF_BOUNDS_NO_POE, NO_SIGNING_CERTIFICATE_FOUND, TIMESTAMP_ORDER_FAILURE. Chacun est soutenu par urn:etsi:019102:subindication:<CASE_NAME> avec le nom de cas exact.

  • Des rapports en entrée, des rapports en sortie. Les quatre points d’entrée du moteur renvoient un ValidationReport pour une entrée hostile au lieu de lever. Une SignatureExtractionException capturée est routée vers le chemin de garde ; une PathValidationException capturée correspond à TOTAL_FAILED / CERTIFICATE_CHAIN_GENERAL_FAILURE.
  • Ordre de la validation basique. Contrôle de format d’abord ; une structure non analysable est TOTAL_FAILED / FORMAT_FAILURE (EN 319 102-1 §5.3.4). Ensuite l’empreinte (HASH_FAILURE) et la vérification cryptographique (SIG_CRYPTO_FAILURE), correspondant aux résultats du bloc de construction EN 319 102-1 §5.2.7.4. L’empreinte est recalculée par le vérificateur et comparée à l’attribut signé messageDigest (RFC 5652 §5.6) ; les empreintes fournies par le producteur ne sont jamais dignes de confiance.
  • Les algorithmes faibles dégradent. Une signature qui se vérifie sous SHA-1, ou avec une liaison de certificat de signature faible, renvoie INDETERMINATE / CRYPTO_CONSTRAINTS_FAILURE, jamais TOTAL_PASSED. Le chemin temporel réaffirme cela afin qu’une signature faible ne soit jamais blanchie en un succès valide dans le temps.
  • Contrôle de provenance de révocation. Les drapeaux de révocation de l’extracteur ne sont consultés que lorsque l’extracteur a effectivement effectué un contrôle de révocation (revocationChecked à vrai). Un défaut non contrôlé n’est ni « vérifié non révoqué » ni un déclencheur REVOKED. La preuve de révocation est établie par le chemin DSS.
  • Propagation des non-succès. Les chemins temporel et long terme ne rehaussent jamais un résultat basique en non-succès. Une seule exception existe : un INDETERMINATE / REVOKED basique est résolu par rapport à $claimedTime ; une révocation au moment revendiqué ou avant est TOTAL_FAILED / REVOKED. Cela reflète le motif EN 319 102-1 §5.3.4 de résolution d’un indéterminé lié à la révocation avec une preuve temporelle. Lorsque la comparaison ne peut pas être effectuée, le rapport basique non résolu est propagé tel quel.
  • Liaison stricte de l’horodatage de signature (échec fermé ; rupture de compatibilité). Lorsque le CMS porte un attribut non signé id-aa-timeStampToken, sa présence déclenche l’application dans les chemins temporel et long terme ; il n’existe pas de mode avertissement seul. La cardinalité doit être exactement un attribut avec exactement une valeur (EN 319 122-1 §5.3) ; toute autre forme est TOTAL_FAILED / FORMAT_FAILURE. Le jeton doit se vérifier cryptographiquement de bout en bout ; un jeton invérifiable, un conflit de différentiel d’analyseur, ou une non-correspondance d’empreinte est INDETERMINATE / TIMESTAMP_ORDER_FAILURE. Un algorithme d’empreinte non pris en charge ou SHA-1 est INDETERMINATE / CRYPTO_CONSTRAINTS_FAILURE. La règle de liaison est RFC 3161 Appendix A : le messageImprint du jeton doit être égal au hachage des octets de la valeur signature du SignerInfo, comparés en temps constant.
  • Contrôles du chemin long terme. Dans le chemin annoté clause 5.4, l’horodatage de signature lié reçoit en outre une évaluation du certificat TSA au genTime du jeton ; une ancre non fiable est INDETERMINATE / CERTIFICATE_CHAIN_GENERAL_FAILURE, jamais un succès. NetworkPolicy::STRICT_OFFLINE avec un matériel DSS embarqué insuffisant renvoie INDETERMINATE / TRY_LATER. La preuve d’existence, la révocation DSS et les constats de chaîne d’archivage court-circuitent chacun vers INDETERMINATE avec une sous-indication mappée.
  • Contrôles de la chaîne d’archivage. L’absence de DocTimeStamp est INDETERMINATE / NO_POE. Un ByteRange structurellement non conforme est TOTAL_FAILED / FORMAT_FAILURE. Chaque jeton doit se vérifier, lier son empreinte aux octets exacts couverts par le ByteRange, et passer le mappage de facette TSA-at-genTime (EXPIRED, NOT_YET_VALID, REVOKED_CA_NO_POE, CERTIFICATE_CHAIN_GENERAL_FAILURE, ou TRY_LATER en mode strict-offline). L’ordre est appliqué : genTime non décroissant, couverture strictement progressive, et jetons ultérieurs contenant le trou /Contents du jeton précédent. Le dernier jeton doit couvrir l’octet final ; les octets en fin sont TIMESTAMP_ORDER_FAILURE. Un genTime de plus de 300 secondes en avance sur l’horloge du vérificateur est TIMESTAMP_ORDER_FAILURE.
  • Les diagnostics ne décident jamais. Les entrées de preuve d’existence DiagnosticData::$timestamps relèvent uniquement de la piste d’audit. Elles ne changent jamais une indication, et l’accumulateur se réinitialise à chaque point d’entrée.
  • Les limites Pki précèdent la crypto. Les plafonds PathValidationOptions (profondeur 32, fan-out de politique 64, 5 s et 10 Mio par récupération) sont contrôlés avant tout travail coûteux. PathValidationResult::$trustAnchorTrusted est distinct de $valid ; requireTrustedAnchor rend invalide un terminus non affirmé. strict() active requireExplicitPolicy, le transport de révocation à échec strict, et requireTrustedAnchor. La validité de chemin est relative à l’ancre selon RFC 5280 §6.1 : un chemin valide commence à une ancre de confiance fournie en entrée.
  • Surface par lots. BatchSignatureValidator::validate() lève InvalidArgumentException pour une liste vide et rejette les lots au-delà de 1000 documents via une garde de ressource. PHP est propriétaire de toute la validation cryptographique dans ce pipeline.
  • Le moteur par défaut n’a pas d’extracteur. new AdESValidationEngine() n’effectue que des contrôles de garde : une signature ou des données signées vides sont TOTAL_FAILED ; toute paire non vide se résout en INDETERMINATE / NO_SIGNING_CERTIFICATE_FOUND, jamais TOTAL_PASSED. Injecte NextPDF\Enterprise\Security\Validation\CmsSignatureDataExtractor pour obtenir une vérification cryptographique.
  • Le contrôle de confiance TSA par défaut n’a pas de magasin. Chaque chaîne TSA renvoie alors « non fiable », de sorte que les résultats d’horodatage de signature d’archivage et à long terme restent INDETERMINATE. Fournis des ancres via validateArchivalTimestampChain(..., $anchors) ou un TsaCertificateAtGenTimeCheck configuré.
  • $pdfBytes vide. validateArchivalTimestampChain('') renvoie TOTAL_FAILED / FORMAT_FAILURE.
  • Les horodatages de signature d’avant le correctif ne peuvent pas passer. Les jetons produits par des versions de NextPDF antérieures au correctif de liaison stricte ont empreinté une entrée différente. Ils échouent à la liaison Appendix A de façon permanente ; re-signe et re-horodate pour rétablir un résultat positif. C’est une rupture de compatibilité délibérée et documentée.
  • DocTimeStamps dupliqués ou chevauchants. Un doublon de même révision, une couverture égale ou chevauchante, ou un jeton ultérieur qui ne contient pas le trou de signature du jeton précédent échoue au contrôle d’ordre.
  • Le scanner est total et au niveau octet. scan() ignore silencieusement les candidats malformés ou usurpés ; un /ByteRange leurre à l’intérieur d’un flux de contenu est rejeté. Il ne résout pas les objets indirects ni ne parcourt la table de références croisées.
  • Couverture, pas atteignabilité. validateArchivalTimestampChain() prouve une couverture cryptographique de plage d’octets jusqu’à la fin de fichier. L’analyse d’atteignabilité au niveau objet (par exemple, une racine de document repointée à l’intérieur d’une révision couverte) est déclarée hors périmètre.
  • L’usage direct de Pki lève. Appeler directement les implémentations de PathValidatorInterface fait remonter PathValidationException pour des chaînes structurellement invalides, des plafonds franchis, des formes de contrainte non prises en charge, et un échec d’export PEM d’un handle OpenSSLCertificate. Le moteur capture cette classe ; tes propres appelants doivent la gérer.

Le côté vérification accepte RSA PKCS#1 v1.5 avec SHA-2 et ECDSA sur P-256/P-384/P-521. Les jetons RSASSA-PSS, EdDSA et SHA-3 échouent fermé comme non pris en charge ; SHA-1 se dégrade en CRYPTO_CONSTRAINTS_FAILURE. Sous le profil de politique cryptographique Enterprise FIPS 140-3 (documenté avec le module de sécurité), la contrainte porte sur les algorithmes acceptés ; le flux de validation lui-même — recalcul d’empreinte, contrôles de signature, liaison, validation de chemin — reste inchangé. NextPDF ne détient aucun certificat FIPS 140-3 et cette page n’en revendique aucun.

AffirmationStandardClause
La validation de signature basique est un bloc de construction réutilisable pour la validation d’horodatage et avec temps.ETSI EN 319 102-1§5.3.1
Un échec d’intégrité correspond à HASH_FAILURE ; un contrôle de signature échoué correspond à SIG_CRYPTO_FAILURE.ETSI EN 319 102-1§5.2.7.4
Le contrôle de format s’exécute en premier et un non-succès arrête le processus.ETSI EN 319 102-1§5.3.4
Un indéterminé lié à la révocation peut être résolu avec une preuve temporelle.ETSI EN 319 102-1§5.3.4
Un chemin de certification valide commence à une ancre de confiance fournie en entrée.RFC 5280§6.1
Le vérificateur recalcule l’empreinte du contenu ; elle doit être égale à l’attribut signé messageDigest.RFC 5652§5.6
Le messageImprint de l’horodatage de signature hache la valeur du champ signature du SignerInfo.RFC 3161Appendix A
L’attribut signature-time-stamp porte exactement un AttributeValue.ETSI EN 319 122-1§5.3

Toutes les clauses sont paraphrasées ; NextPDF ne reproduit pas le texte normatif. NextPDF ne formule aucune revendication de conformité ou de certification AdES / PAdES. La prise en charge d’un standard n’est pas une conformité à celui-ci, et la conformité n’est pas une certification — NextPDF ne détient aucune certification et n’en accorde aucune. Le moteur implémente les procédures de validation citées en tant que capacité ; ce n’est pas un service de validation qualifié ou certifié, et un rapport TOTAL_PASSED est une affirmation cryptographique, pas une détermination juridique. Les valeurs d’énumération réutilisent le motif d’identifiant URN ETSI pour l’interopérabilité des données de rapport ; cette réutilisation n’affirme aucune approbation.

  • Mappage des étiquettes de clause. La source du paquet annote les points d’entrée comme les clauses EN 319 102-1 5.2, 5.3 et 5.4. Le corpus de conformité place le processus de validation de signature basique lui-même à la clause 5.3, avec le bloc de construction cryptographique à 5.2.7.4. Cette page cite les numéros de clause récupérés ; le contrat de comportement, et non l’étiquette, fait autorité.
  • Tests déterministes. Chaque comparaison temporelle passe par le ClockInterface PSR-20 injecté. Injecte une horloge figée pour tester les contrôles de fenêtre, la borne de dérive de genTime de 300 secondes, et les décisions de fraîcheur de CRL.
  • Composition. Tous les collaborateurs du moteur sont injectés par constructeur et optionnels, avec des défauts en échec fermé. Le validateur de chemin par défaut est CertificateChainValidator::withDefaults() sur l’horloge du moteur ; les options par défaut maintiennent le traitement des politiques et des contraintes de nom comme un no-op pour des entrées conformes et non contraintes.
  • Espaces de noms. La surface du moteur réside dans NextPDF\Enterprise\Security\Validation, la surface de validation de chemin dans NextPDF\Enterprise\Security\Pki, et l’orchestrateur de lots dans NextPDF\Enterprise\Signature.
  • Hygiène des rapports. Les rapports sont immuables et sérialisables via toArray(). Le contexte de diagnostic se réinitialise à chaque point d’entrée, de sorte qu’un rapport ne porte jamais de preuve d’une exécution antérieure sur la même instance du moteur.

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