Aller au contenu
getnextpdf.com

Enterprise édition

Démarrage rapide de NextPDF Enterprise

Ce tutoriel te fait passer d’un projet vide à deux résultats Enterprise fonctionnels. D’abord tu vérifies un PDF signé existant et tu lis son MainIndication. Ensuite tu élèves un document signé au niveau PAdES B-LT avec le producteur longue conservation. Chaque étape montre la sortie ou l’exception exacte à laquelle tu dois t’attendre. NextPDF documente une capacité, pas une certification : il ne détient aucune certification PAdES ou eIDAS et n’en accorde aucune.

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

  • Composer est configuré pour le dépôt privé NextPDF. Suis d’abord Installer et s’authentifier.
  • Tu disposes de ton enveloppe de licence Enterprise, téléchargée depuis ton compte sur app.getnextpdf.com. Licence et activation explique ce qu’est l’enveloppe et où elle va.
  • Pour l’étape 3, tu as besoin d’un PDF signé à vérifier. Pour la partie B-LT, il te faut aussi ton certificat de signataire et un accès réseau aux répondeurs OCSP/CRL.

Requiers le paquet Enterprise. Il dépend de nextpdf/core et nextpdf/pro, donc Composer récupère toute la pile :

Fenêtre de terminal
composer require nextpdf/enterprise
composer show nextpdf/enterprise

Si composer show affiche le paquet et sa version, l’installation a réussi. Place maintenant l’enveloppe de licence signée là où ton déploiement la charge, exactement comme le décrit Licence et activation. Installer le paquet seul n’accorde pas les capacités Enterprise ; c’est la licence activée qui sélectionne l’édition.

Demande à l’évaluateur d’habilitation ce que ta licence accorde. Ton amorçage obtient la NextPDF\Enterprise\Licensing\LicenseKey vérifiée pendant l’activation ; passe-la en argument :

<?php
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Licensing\EntitlementEvaluator;
use NextPDF\Enterprise\Licensing\LicenseKey;
/** @var LicenseKey|null $license The verified license from activation. */
$result = (new EntitlementEvaluator())->evaluate($license);
echo 'status: ' . $result->status->value . PHP_EOL;
echo 'edition: ' . ($result->edition?->value ?? 'none') . PHP_EOL;
echo 'runtime: ' . ($result->runtimeAllowed ? 'allowed' : 'disabled') . PHP_EOL;

Avec une licence Enterprise active, tu vois :

status: active
edition: enterprise
runtime: allowed

La méthode derrière cette étape :

public function evaluate(?LicenseKey $license, ?DateTimeImmutable $now = null): EntitlementResult

Lève ou échoue avec : elle ne lève jamais d’exception. Une licence absente renvoie un EntitlementResult fermé par défaut, avec EntitlementStatus::NoLicense et runtimeAllowed à false (voir l’étape 4).

Extrais la signature d’un PDF signé, puis exécute la validation AdES de base. Le moteur implémente les niveaux de validation de l’ETSI EN 319 102-1 ; validateBasic() est le flux de la clause 5.2 — structure, condensat, cryptographie de la signature et chaîne de certificats :

<?php
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Validation\AdESValidationEngine;
use NextPDF\Enterprise\Security\Validation\CmsSignatureDataExtractor;
use NextPDF\Enterprise\Signature\SignatureExtractor;
$pdf = file_get_contents(__DIR__ . '/contract-signed.pdf');
if ($pdf === false) {
throw new RuntimeException('Could not read contract-signed.pdf');
}
$signatures = (new SignatureExtractor())->extract($pdf);
if ($signatures === []) {
throw new RuntimeException('The PDF carries no signature dictionary.');
}
$engine = new AdESValidationEngine(extractor: new CmsSignatureDataExtractor());
$report = $engine->validateBasic(
$signatures[0]['signedBytes'], // the exact /ByteRange-covered bytes
$signatures[0]['contents'], // the DER CMS SignedData from /Contents
);
echo $report->mainIndication->name . PHP_EOL;
echo ($report->subIndication?->name ?? '(none)') . PHP_EOL;

Pour une signature bien formée qui passe les contrôles structurels, de condensat, cryptographiques et de chaîne de base configurés dans cet exemple, tu vois :

TOTAL_PASSED
(none)

MainIndication a exactement trois cas : TOTAL_PASSED, TOTAL_FAILED et INDETERMINATE. Le moteur est fermé par défaut : un contrôle qu’il ne peut pas établir positivement donne INDETERMINATE, jamais un passage silencieux. Un passage ici est un résultat de validation selon les contrôles de ce moteur, pas une déclaration de confiance ou de certification — les ancres de confiance et les preuves de longue conservation relèvent des niveaux plus profonds sur la page de vérification.

public function extract(string $pdfData): array

Lève ou échoue avec : InvalidArgumentException si l’entrée n’est pas un PDF valide. Un /ByteRange ou un /Contents malformé donne des chaînes vides (fermé par défaut), jamais un résultat positif.

public function validateBasic(string $signedData, string $signature): ValidationReport

Lève ou échoue avec : elle ne lève jamais d’exception sur un échec de vérification. Chaque défaut se traduit par une indication de ValidationReport, par exemple HASH_FAILURE ou SIG_CRYPTO_FAILURE.

Fais maintenant passer un document fraîchement signé au niveau B-LT. Le producteur longue conservation collecte la chaîne de certificats plus les preuves OCSP/CRL et écrit le Document Security Store (DSS). Il prolonge la passe de signature décrite sur la page Signature, qui te fournit le tampon de sortie, le registre d’objets et le hex /Contents de la signature :

use NextPDF\Enterprise\Security\Ltv\LtvManager;
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\SignatureLevel;
$certInfo = CertificateInfo::fromPkcs12('/secure/signer.p12', $p12Password);
// $httpClient is any PSR-18 client; it fetches OCSP responses and CRLs.
$ltv = new LtvManager($certInfo, $httpClient, level: SignatureLevel::PAdES_B_LT);
// $buffer, $registry, and $signatureContentsHex come from the signing pass.
$dssObjectNumber = $ltv->enableLtv($buffer, $registry, $signatureContentsHex);

La valeur de retour est le numéro d’objet DSS pour l’entrée /DSS du catalogue du document. Le producteur applique par défaut l’enforcement strict de la révocation : un matériel de révocation manquant lève une exception au lieu d’émettre silencieusement un fichier « B-LT » creux.

public function enableLtv(BinaryBuffer $buffer, ObjectRegistry $registry, string $signatureContentsHex): int

Lève ou échoue avec : NextPDF\Enterprise\Security\Ltv\LtvException lorsque la validation de la chaîne échoue, lorsque le certificat est révoqué, ou lorsque le matériel de révocation est manquant sous le mode strict par défaut.

status: no_license — l’enveloppe n’est pas chargée

Section intitulée « status: no_license — l’enveloppe n’est pas chargée »

L’étape 2 affiche status: no_license et runtime: disabled, et le résultat porte l’avertissement No license configured. Enterprise runtime is disabled. Install a license or purchase one at https://nextpdf.dev/pricing. Un appel soumis à habilitation lève alors NextPDF\Accelerator\Exception\SpectrumAuthenticationException avec le code SPEC-LIC-001, par exemple Capability '...' requires a valid license. Correctif : place et active l’enveloppe selon Licence et activation, puis relance l’étape 2.

InvalidArgumentException: Input does not start with %PDF header

Section intitulée « InvalidArgumentException: Input does not start with %PDF header »

SignatureExtractor::extract() a reçu quelque chose qui n’est pas un PDF — un mauvais chemin, une lecture vide ou un téléchargement compressé. Vérifie le fichier que tu as chargé. Une liste $signatures vide est différente : le fichier est un PDF, mais il ne porte aucun dictionnaire /Type /Sig, donc il n’y a rien à vérifier.

LtvException: Strict revocation: LTV warning: no revocation data for certificate at chain position 0

Section intitulée « LtvException: Strict revocation: LTV warning: no revocation data for certificate at chain position 0 »

enableLtv() n’a pas pu obtenir de réponse OCSP ni de CRL pour un certificat de la chaîne, et le mode strict par défaut refuse d’écrire une revendication B-LT sans preuve. Vérifie l’accessibilité du répondeur depuis l’hôte, ou passe enforcementMode: RevocationEnforcementMode::PERMISSIVE uniquement si tu acceptes explicitement une exécution en mode avertissement seul — n’étiquette jamais une telle sortie comme B-LT pour des workflows de production ou de conformité, sauf si l’absence de preuve de révocation est explicitement acceptée et documentée. Connexe : demander B-LTA sans client TSA échoue avec LtvException: TSA client required for document timestamps.