Signer à grande échelle, sans compromis
Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8Spec: ETSI EN 319 142-1ETSI EN 319 142-1Spec: RFC 5652, §5.1RFC 5652 §5.1
Signer un seul document est une opération cryptographique. En signer cent mille pour une échéance, c’est la même opération, répétée, où la défaillance dangereuse n’est plus « c’était lent » mais « l’un d’eux est parti non signé et personne ne l’a remarqué ». Cette page traite de la seconde chose sans renoncer à la première : signature en masse et en parallèle où chaque signature reste correcte, où l’exécution refuse d’émettre un fichier qu’elle n’a pas pu signer, et où un gros travail reprend au lieu de tout reprendre depuis le début.
Pourquoi c’est important
Section intitulée « Pourquoi c’est important »Une signature est un fait propre à chaque document. Son condensé est calculé sur une plage d’octets déclarée qui exclut la valeur de la signature elle-même (Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8), si bien qu’il n’existe aucune manière honnête de signer un millier de documents « en lot » d’un seul geste — chacun porte sa propre structure CMS SignedData sur ses propres octets (Spec: RFC 5652, §5.1RFC 5652 §5.1). L’échelle multiplie donc les occasions pour qu’exactement une chose tourne mal en silence : une poignée de clé qui a brièvement échoué, une autorité d’horodatage qui a expiré, un worker qui est mort en tenant un fichier à demi écrit.
Le résultat coûteux n’est pas un plantage. Un plantage est bruyant, et tu le rejoues. Le résultat coûteux est silencieux — un PDF non signé qui a l’air terminé, posé dans une archive, découvert des mois plus tard par le validateur d’un auditeur. À grande échelle, « en grande partie signé » est indiscernable de « signé » jusqu’au moment précis où celui qui compte est vérifié. Tout l’enjeu de signer à grande échelle est de rendre ce résultat structurellement impossible, et non statistiquement rare.
La version courte
Section intitulée « La version courte »- Chaque document est signé individuellement, sur sa propre plage d’octets. « Lot » est un mot d’ordonnancement, pas un mot cryptographique. Il n’y a pas de signature partagée.
- Le niveau est un contrat, pas une indication. Tu nommes un niveau de référence PAdES et le moteur produit exactement ce niveau pour chaque document, ou il fait échouer ce document bruyamment (Spec: ETSI EN 319 142-1ETSI EN 319 142-1).
- Le pipeline est à fermeture en cas d’échec. Un document qui ne peut pas être signé correctement ne passe pas comme de simples octets. Il est retenu, non transmis.
- La concurrence est par document, et sûre par construction. Les unités de signature ne partagent aucun état mutable, si bien que deux workers ne peuvent pas corrompre la sortie l’un de l’autre.
- Les grandes exécutions sont durables. Une sortie validée n’est pas réémise lors de la reprise ; une exécution interrompue continue depuis son dernier point de contrôle au lieu de tout resigner.
L’approche de NextPDF
Section intitulée « L’approche de NextPDF »La conception repose sur une seule séparation : produire la signature est une petite étape déterministe propre à chaque document ; en exécuter des milliers sans risque est une étape d’orchestration. Garder ces deux choses séparées est ce qui permet à chacune de rester simple.
L’étape de signature est celle qui ne doit jamais transiger. Tu demandes un niveau — un cas
d’énumération SignatureLevel, jamais une chaîne que le moteur doit interpréter — et ce
niveau est traité comme un contrat pour ce document. Le moteur produit le niveau demandé
ou s’arrête sur une erreur exploitable ; il ne signe pas discrètement à un niveau inférieur
en laissant un enregistrement en revendiquer un plus élevé. La correction ne se relâche pas
parce qu’il y a plus de documents derrière celui-ci. La cent-millième signature est calculée
avec exactement le même soin que la première.
La règle de fermeture en cas d’échec est ce qui rend cela digne de confiance à grande
échelle. Le chemin de signature de NextPDF refuse d’émettre un artefact d’apparence plausible
mais non signé à la place de celui que tu as demandé. La voie d’application prise en charge
est l’API Document de haut niveau : tu configures la signature avec
Document::setSignature() puis tu réclames les octets avec Document::getPdfData() (ou
save() / output()), et cette unique passe d’écriture soit émet un PDF correctement signé,
soit lève une exception avant de rendre des octets — jamais un fichier non signé que
l’appelant croit signé. Appliquée à travers un lot, c’est la règle qui transforme « l’un
d’eux est passé non signé » d’un défaut latent silencieux en un unique travail échoué et
rejouable.
- Warm the signing material onceOn worker boot, open the key/certificate source and the timestamp client. This cost is paid once per worker, not once per document.
- Enqueue the documentsA queue holds the per-document jobs. The queue is the throughput dial — signing workers scale horizontally behind it.
- Render and sign one documentA disposable unit renders the document, then signs it over its own byte range at the requested PAdES level. Nothing is shared with the next document.
- Commit on success, hold on failureA correctly-signed file commits once. A document that could not be signed is failed and retried — never emitted as unsigned bytes.
- Checkpoint, and resume on crashA durable run records what has committed. After a crash it continues from the last checkpoint instead of re-signing the whole batch.
Core te donne la correction cryptographique : signature logicielle CMS et PAdES B-B (avec B-T via le client d’horodatage) où chaque document est signé individuellement et à fermeture en cas d’échec. L’orchestration qui rend une grande exécution durable, concurrente et exactement-une-fois — le moteur de rendu sans effet de bord, plus le validateur, le point de contrôle, l’idempotence et les magasins de lettres mortes — est le module Stream des éditions avancées ; la signature matérielle via un HSM ou un KMS dans le cloud est de même une couture des éditions avancées. Core prouve que chaque signature est correcte ; les éditions avancées rendent un million d’entre elles survivables.
Exemple pratique
Section intitulée « Exemple pratique »La forme ci-dessous est l’unité de signature par document à l’intérieur d’une boucle de lot. Chaque itération signe un document à un niveau nommé et produit soit un résultat correctement signé, soit fait échouer ce seul travail — elle ne renvoie jamais des octets non signés déguisés en résultat.
<?php
declare(strict_types=1);
use NextPDF\Contracts\DocumentFactoryInterface;use NextPDF\Security\Signature\CertificateInfo;use NextPDF\Security\Signature\SignatureLevel;use NextPDF\Exception\SignatureException;use Psr\Log\LoggerInterface;
/** * One signing-batch iteration: render, sign at a named level, commit or fail. * * The factory and the certificate source ($certInfo, the warmed signing * material) are process-lifetime singletons; the document is disposable. A * document that cannot be signed at the requested level fails this job loudly — * it is never committed unsigned. * * @param iterable<int, callable(\NextPDF\Core\Document): \NextPDF\Core\Document> $jobs */function signBatch( DocumentFactoryInterface $factory, CertificateInfo $certInfo, LoggerInterface $logger, iterable $jobs,): void { // The level is an explicit, ordered contract — not a flag we hope is honoured. $level = SignatureLevel::PAdES_B_T;
foreach ($jobs as $jobId => $build) { // Fresh, disposable unit — shares the warmed signing material only. $doc = $factory->create(); $doc = $build($doc);
try { // Sign over this document's own byte range, at exactly $level, // or throw. There is no "signed lower, reported higher" path. $doc->setSignature(certInfo: $certInfo, level: $level); $signed = $doc->getPdfData(); } catch (SignatureException $e) { // Fail-closed: this document does NOT continue as unsigned bytes. // The job is failed and left for retry / dead-letter handling. $logger->error('pdf.sign.failed', ['job_id' => $jobId, 'reason' => $e->getMessage()]); continue; }
// Only a correctly-signed result reaches the commit step. commitSignedOutput($jobId, $signed); unset($doc, $signed); // release per-document state before the next iteration
$logger->info('pdf.sign.committed', ['job_id' => $jobId, 'level' => $level->value]); }}Le catch est la ligne porteuse. Il fait la différence entre une exécution qui retient les
documents qu’elle n’a pas pu signer et une exécution qui les expédie quand même. Le
continue ne masque pas l’échec — le travail est enregistré et laissé pour réessai, si bien
que le lot se termine avec une liste connue et complète de ce qui a été signé et de ce qui ne
l’a pas été, jamais avec un trou silencieux.
Idée fausse courante
Section intitulée « Idée fausse courante »La première idée fausse est que « signature en lot » signifie une seule signature appliquée à de nombreux fichiers. Ce n’est pas le cas, et tout système qui le prétend ne produit pas de signatures PAdES valides — le condensé de chaque document est lié à ses propres octets (Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8). « Lot » concerne purement combien et à quelle vitesse, jamais le partage de l’unité cryptographique.
La deuxième est que la concurrence signifie relâcher la correction au profit de la vitesse — qu’un signataire rapide doive couper un coin que le signataire soigneux ne coupe pas. Ce n’est pas le cas. Comme les unités de signature ne partagent aucun état mutable, les exécuter en parallèle change l’ordonnancement, pas les octets. Chaque signature parallèle est calculée avec la même rigueur qu’une seule ; le parallélisme se situe dans l’orchestration autour d’elles.
La troisième est que la durabilité est quelque chose que l’on rapporte après la première exécution nocturne échouée. À ce moment-là, tu as déjà perdu l’exécution. Un pipeline reprenable doit savoir, par document, ce qui a été validé et ce qui ne l’a pas été avant le plantage — ce qui est exactement ce que les magasins de point de contrôle et d’idempotence existent pour enregistrer.
Limites et périmètre
Section intitulée « Limites et périmètre »- Chaque signature est par document et liée aux normes ; il n’y a pas de raccourci de lot. Le volume change l’ordonnancement, pas l’unité cryptographique. NextPDF signe chaque document sur sa propre plage d’octets.
- Core fait la signature logicielle CMS et PAdES B-B (B-T via un client d’horodatage). Le moteur de rendu-et-signature durable, concurrent et exactement-une-fois est le module Stream des éditions avancées ; la garde de clé adossée à un HSM/KMS est une couture des éditions avancées. Cette page ne revendique pas cette orchestration comme faisant partie de Core.
- La fermeture en cas d’échec est le comportement du moteur, pas une garantie sur ton
câblage. NextPDF refuse d’émettre un fichier non signé mais cru signé et expose la voie de
signature prise en charge. Un pipeline qui attrape l’erreur résultante et valide quand même
a choisi de défaire la garantie — le cadrage que le
catch/continuede l’exemple existe pour empêcher. - Le niveau PAdES est appliqué par document, non certifié pour l’exécution. Le moteur produit le niveau de référence demandé ou échoue ; c’est une application structurelle, non un verdict de conformité tiers sur les fichiers produits. La progression des niveaux elle-même est traitée dans Profils de référence PAdES.
- La file d’attente, la garde de clé, l’autorité d’horodatage et le magasin d’objets sont les tiens. NextPDF fournit la correction de signature par document et, dans les éditions avancées, les primitives d’orchestration durable. Il n’exploite pas ton infrastructure et ne se porte pas garant de ta TSA.
| Edition | Availability |
|---|---|
| Core | Signature logicielle CMS par document, PAdES B-B (B-T avec un client d’horodatage), signée individuellement sur la propre plage d’octets de chaque document, à fermeture en cas d’échec contre une sortie silencieusement non signée. La simple signature par document ne requiert aucun palier commercial. |
| Pro | Ajoute le module Stream : un moteur de rendu sans effet de bord, plus un validateur durable, un point de contrôle, l’idempotence et des magasins de lettres mortes — des exécutions de lot concurrentes, résistantes aux plantages et exactement-une-fois qui reprennent au lieu de recommencer. |
| Enterprise | Ajoute la garde de clé adossée au matériel (HSM via PKCS#11, ou un KMS dans le cloud) pour que la clé privée ne quitte jamais le périphérique, ainsi que les niveaux PAdES à long terme (B-LT, B-LTA) qui maintiennent une archive à fort volume vérifiable pendant des décennies. |
Documents associés
Section intitulée « Documents associés »- Génération de documents à fort volume — le modèle de lot à mémoire bornée et mis en file d’attente sur lequel cette page signe ; lis-la d’abord pour la discipline de débit et de mesure.
- Profils de référence PAdES — ce que chaque niveau (B-B à B-LTA) ajoute, pour que tu signes au niveau que l’obligation requiert.
- Comment les signatures sont intégrées dans un PDF — le socle de plage d’octets et de dictionnaire qui rend une signature propre à chaque document.
- Signature adossée à un HSM — où se situe la frontière de la clé privée quand le matériel de signature vit dans le matériel.
- Stream (Pro) — le moteur de rendu durable, concurrent et exactement-une-fois qui transforme une unité de signature unique en une exécution reprenable.
Glossaire
Section intitulée « Glossaire »- Signature en lot — signer de nombreux documents selon un ordonnancement. Un concept d’ordonnancement ; chaque document est tout de même signé individuellement sur ses propres octets.
- Fermeture en cas d’échec (fail-closed) — sur une défaillance qui produirait sinon une sortie non signée ou erronée, le pipeline retient le document et signale, plutôt que de le transmettre comme de simples octets.
- Validation exactement-une-fois — une propriété de pipeline durable où une sortie correctement signée est publiée une seule fois et n’est pas réémise lorsqu’une exécution interrompue reprend.
- Point de contrôle — enregistrement durable, par document, de ce qui a été validé, pour qu’une exécution puisse continuer là où elle s’est arrêtée au lieu de tout resigner.
- CMS SignedData — le conteneur cryptographique des signatures sur du contenu (il peut porter plusieurs signataires) ; ce pipeline produit la signature PDF d’un signataire par document, l’unité par document qu’un lot produit.
- PAdES — PDF Advanced Electronic Signatures, la famille de profils ETSI EN 319 142 pour la signature PDF ; ses niveaux de référence vont de B-B à B-LTA.