Inspecter une signature existante et comprendre la frontière de confiance
Cette recette utilise l’inspecteur Core pour détecter si un PDF contient une signature, puis pose la frontière de confiance. Détecter une signature ne revient pas à la vérifier. La vérification cryptographique, la validation du chemin de confiance et le contrôle de révocation relèvent de Premium ou d’un outil externe.
Prérequis
Section intitulée « Prérequis »- Core installé :
composer require nextpdf/core:^3. - Un fichier PDF à inspecter.
- Lis les octets du PDF.
- Crée un
Inspectoret appelleinspect(). - Lis
InspectResult::$hasSigned.truesignifie qu’un dictionnaire de signature est présent dans le fichier. - Lis
InspectResult::$isEncryptedet les indicateurs de risque pour situer le contexte. - Transmets le fichier à un vérificateur pour obtenir la décision cryptographique. L’inspecteur signale une présence, pas une validité.
Le schéma ci-dessous met en évidence deux points : la frontière que cette recette rend explicite, la présence n’est pas la validité ; et l’ensemble complet des contrôles qu’une véritable vérification doit encore effectuer.
Exemple complet
Section intitulée « Exemple complet »<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\Inspector;use NextPDF\Inspect\InspectConfig;
$pdfData = file_get_contents(__DIR__ . '/incoming.pdf');if ($pdfData === false || $pdfData === '') { fwrite(STDERR, "Cannot read incoming.pdf\n"); exit(1);}
$inspector = new Inspector();
// InspectConfig::quick() selects InspectDepth::Quick. This is the only// depth that runs offline: a default Inspector has no Spectrum sidecar,// and without a sidecar Quick is the sole path that returns a result.// Standard and Full require the sidecar (see the SIDECAR-001 edge case).$result = $inspector->inspect( $pdfData, InspectConfig::quick(),);
// hasSigned reports the PRESENCE of a signature dictionary.// It does NOT mean the signature verifies.if ($result->hasSigned) { echo "A signature is present in incoming.pdf\n"; echo "Encrypted: " . ($result->isEncrypted ? 'yes' : 'no') . "\n"; echo "Next step: run a cryptographic verifier before trusting it.\n";} else { echo "No signature found in incoming.pdf\n";}Sortie attendue
Section intitulée « Sortie attendue »Pour une entrée signée :
A signature is present in incoming.pdfEncrypted: noNext step: run a cryptographic verifier before trusting it.Pour une entrée non signée :
No signature found in incoming.pdfCas limites
Section intitulée « Cas limites »- La présence n’est pas la validité — frontière.
InspectResult::$hasSignedindique qu’un dictionnaire de signature existe dans le fichier. Il ne vérifie ni la structure CMS, ni le condensat de la plage d’octets, ni le certificat de signature, ni la chaîne de certification, ni l’état de révocation. Un fichier altéré peut tout de même signalerhasSigned = true. Ne traite jamais la présence comme une preuve d’intégrité ou de paternité. - Ce qu’exige une vérification complète. Pour prendre une décision complète, le vérificateur recalcule le condensat de la plage d’octets et le compare (ISO 32000-2 §12.8.1), valide le CMS SignedData, construit et vérifie le chemin X.509 jusqu’à un ancrage de confiance, puis contrôle la révocation via OCSP ou CRL. Pour les entrées à long terme, les données de validation résident dans le DSS (ETSI EN 319 142-2 §6.3.1). Ces opérations passent par les contrats
SignerInterfaceetLtvManagerInterface; les implémentations de production sont livrées dans les éditions Pro et Enterprise. L’autre chemin pris en charge consiste à utiliser un validateur externe. - Profondeur d’inspection et sidecar (SIDECAR-001). Par défaut, un
new Inspector()n’a aucun sidecar Spectrum configuré. Sans sidecar, seulInspectDepth::Quickrenvoie un résultat.InspectDepth::Quickutilise le repli PHP dans le processus courant.InspectDepth::StandardetInspectDepth::Fullrequièrent tous deux le sidecar. En l’absence de sidecar, ils lèvent uneInspectExceptionavec le codeINSPECT-SIDECAR-001(“Spectrum sidecar is required for Standard/Full depth inspection”,retryable = true). Le constructeurInspectConfiga pour profondeur par défautStandard. Par conséquent, un simplenew InspectConfig()(ounew InspectConfig(depth: InspectDepth::Standard)) n’est pas utilisable hors ligne. Il lève SIDECAR-001 avant même quehasSignedne soit lu. UtiliseInspectConfig::quick()pour la détection de présence hors ligne, comme dans cette recette. Aucune des profondeurs n’effectue de vérification cryptographique de signature dans Core. - Entrée vide. Une chaîne vide lève une
InspectExceptionavec le codeINSPECT-INPUT-001. Protège l’étape de lecture. - Signatures multiples. L’indicateur de présence ne compte pas les signatures et ne distingue pas une signature d’approbation d’un horodatage de document. Utilise un vérificateur dédié quand le nombre de signatures ou le verdict par signature a de l’importance.
Conformité
Section intitulée « Conformité »| Énoncé | Spécification | Clause | reference_id |
|---|---|---|---|
La valeur de signature est stockée dans l’entrée Contents du dictionnaire de signature. | ISO 32000-2 | §12.8.1 | |
La vérification recalcule le condensat sur le ByteRange, en excluant la valeur de signature. | ISO 32000-2 | §12.8.1 | |
| Les données de validation à long terme résident dans le DSS. | ETSI EN 319 142-2 | §6.3.1 |
Cette recette détecte une signature. Elle n’établit pas que la signature est valide, de confiance ou non révoquée. Cette décision revient à un vérificateur cryptographique.