Signieren im großen Maßstab, ohne Kompromisse
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
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Ein Dokument zu signieren ist eine kryptografische Operation. Hunderttausend unter Termindruck zu signieren ist dieselbe Operation, wiederholt, bei der das gefährliche Versagen nicht mehr „es war langsam” lautet, sondern „eines davon ging unsigniert hinaus und niemand bemerkte es.” Auf dieser Seite geht es darum, das Zweite zu tun, ohne das Erste aufzugeben: Signieren in großer Zahl und nebenläufig, bei dem jede Signatur weiterhin korrekt ist, der Lauf sich weigert, eine Datei auszugeben, die er nicht signieren konnte, und ein großer Auftrag fortsetzt, statt von vorne zu beginnen.
Warum das wichtig ist
Abschnitt betitelt „Warum das wichtig ist“Eine Signatur ist eine Tatsache pro Dokument. Ihr Digest wird über einen deklarierten Byte-Bereich berechnet, der den Signaturwert selbst ausschließt (Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8), sodass es keinen ehrlichen Weg gibt, tausend Dokumente „als Stapel” in einem Zug zu signieren — jedes trägt seine eigene CMS-SignedData über seine eigenen Bytes (Spec: RFC 5652, §5.1RFC 5652 §5.1). Der Maßstab vervielfacht daher die Chancen, dass genau eine Sache leise schiefgeht: ein Schlüssel-Handle, das kurz ausfiel, eine Zeitstempelinstanz, die abbrach, ein Worker, der starb, während er eine halb geschriebene Datei hielt.
Das teure Ergebnis ist kein Absturz. Ein Absturz ist laut, und Sie wiederholen ihn. Das teure Ergebnis ist ein stilles — ein unsigniertes PDF, das fertig aussieht und in einem Archiv liegt, Monate später vom Validator eines Prüfers entdeckt. Im großen Maßstab ist „größtenteils signiert” nicht von „signiert” zu unterscheiden, genau bis zu dem Moment, in dem das eine geprüft wird, auf das es ankommt. Der ganze Sinn des Signierens im großen Maßstab ist, dieses Ergebnis strukturell unmöglich zu machen, nicht statistisch selten.
Die Kurzfassung
Abschnitt betitelt „Die Kurzfassung“- Jedes Dokument wird einzeln signiert, über seinen eigenen Byte-Bereich. Stapel ist ein Wort der Ablaufplanung, kein kryptografisches. Es gibt keine geteilte Signatur.
- Die Stufe ist ein Vertrag, kein Hinweis. Sie benennen eine PAdES-Baseline-Stufe, und die Engine erzeugt genau diese Stufe für jedes Dokument, oder sie lässt dieses Dokument lautstark scheitern (Spec: ETSI EN 319 142-1ETSI EN 319 142-1).
- Die Pipeline ist fail-closed. Ein Dokument, das nicht korrekt signiert werden kann, wird nicht als bloße Bytes durchgereicht. Es wird zurückgehalten, nicht weitergegeben.
- Nebenläufigkeit erfolgt pro Dokument und ist konstruktionsbedingt sicher. Signiereinheiten teilen keinen veränderlichen Zustand, sodass zwei Worker die Ausgabe des jeweils anderen nicht beschädigen können.
- Große Läufe sind dauerhaft. Festgeschriebene Ausgabe wird beim Fortsetzen nicht erneut ausgegeben; ein abgestürzter Lauf setzt von seinem letzten Checkpoint fort, statt alles neu zu signieren.
Wie NextPDF es angeht
Abschnitt betitelt „Wie NextPDF es angeht“Das Design ruht auf einer Trennung: Das Erzeugen der Signatur ist ein kleiner, deterministischer Schritt pro Dokument; Tausende davon sicher auszuführen ist ein Orchestrierungsschritt. Diese auseinanderzuhalten ist es, was jeden einfach hält.
Der Signierschritt ist derjenige, der niemals Kompromisse machen darf. Sie
verlangen eine Stufe — einen SignatureLevel-Enum-Fall, niemals einen String,
den die Engine interpretieren muss — und diese Stufe wird als Vertrag für dieses
Dokument behandelt. Die Engine erzeugt die verlangte Stufe oder hält mit einem
umsetzbaren Fehler an; sie signiert nicht stillschweigend auf einer niedrigeren
Stufe und lässt einen Datensatz eine höhere behaupten. Die Korrektheit lockert
sich nicht, weil mehr Dokumente hinter diesem stehen. Die hunderttausendste
Signatur wird genau so sorgfältig berechnet wie die erste.
Die Fail-closed-Regel ist das, was das im großen Maßstab vertrauenswürdig macht.
Der Signierpfad von NextPDF lehnt es ab, ein plausibel aussehendes, aber
unsigniertes Artefakt anstelle desjenigen auszugeben, das Sie verlangt haben. Der
unterstützte Anwendungsweg ist die hochstufige Document-API: Sie konfigurieren
die Signatur mit Document::setSignature() und verlangen dann die Bytes mit
Document::getPdfData() (oder save() / output()), und dieser eine
Schreibdurchgang gibt entweder ein korrekt signiertes PDF aus oder wirft eine
Ausnahme bevor er Bytes zurückgibt — niemals eine unsignierte Datei, die der
Aufrufer für signiert hält. Über einen Stapel angewandt, ist dies die Regel, die
„eines schlüpfte unsigniert durch” von einem stillen latenten Defekt in einen
einzigen fehlgeschlagenen, wiederholbaren Auftrag verwandelt.
- 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 gibt Ihnen die kryptografische Korrektheit: software-basiertes CMS-Signieren und PAdES B-B (mit B-T über den Zeitstempel-Client), bei dem jedes Dokument einzeln und fail-closed signiert wird. Die Orchestrierung, die einen großen Lauf dauerhaft, nebenläufig und exactly-once macht — die seiteneffektfreie Render-Engine plus die Committer-, Checkpoint-, Idempotenz- und Dead-Letter-Speicher — ist das Stream-Modul in den erweiterten Editionen; hardwaregestütztes Signieren über ein HSM oder ein Cloud-KMS ist ebenso eine Nahtstelle der erweiterten Editionen. Core beweist, dass jede Signatur korrekt ist; die erweiterten Editionen machen eine Million davon überlebbar.
Praktisches Beispiel
Abschnitt betitelt „Praktisches Beispiel“Die Gestalt unten ist die Signiereinheit pro Dokument innerhalb einer Stapelschleife. Jede Iteration signiert ein Dokument auf einer benannten Stufe und liefert entweder ein korrekt signiertes Ergebnis oder lässt genau diesen einen Auftrag scheitern — sie gibt niemals unsignierte Bytes zurück, die als Ergebnis verkleidet sind.
<?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]); }}Das catch ist die tragende Zeile. Es ist der Unterschied zwischen einem Lauf,
der die Dokumente zurückhält, die er nicht signieren konnte, und einem Lauf, der
sie trotzdem ausliefert. Das continue übertüncht das Versagen nicht — der
Auftrag wird festgehalten und für einen erneuten Versuch zurückgelassen, sodass
der Stapel mit einer bekannten, vollständigen Liste dessen endet, was signiert
wurde und was nicht, niemals mit einer stillen Lücke.
Verbreitetes Missverständnis
Abschnitt betitelt „Verbreitetes Missverständnis“Das erste Missverständnis ist, dass „Stapelsignieren” eine Signatur bedeutet, die auf viele Dateien angewandt wird. Tut es nicht, und jedes System, das das behauptet, produziert keine gültigen PAdES-Signaturen — der Digest jedes Dokuments ist an seine eigenen Bytes gebunden (Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8). Stapel geht rein darum, wie viele und wie schnell, niemals darum, die kryptografische Einheit zu teilen.
Das zweite ist, dass Nebenläufigkeit bedeutet, Korrektheit für Geschwindigkeit zu lockern — dass ein schneller Signierer eine Ecke abschneiden müsse, die der sorgfältige nicht abschneidet. Tut sie nicht. Weil Signiereinheiten keinen veränderlichen Zustand teilen, ändert ihre parallele Ausführung den Ablaufplan, nicht die Bytes. Jede parallele Signatur wird mit derselben Strenge berechnet wie eine einzelne; die Parallelität liegt in der Orchestrierung um sie herum.
Das dritte ist, dass Dauerhaftigkeit etwas ist, das man nach dem ersten fehlgeschlagenen Nachtlauf aufsetzt. Bis dahin haben Sie den Lauf bereits verloren. Eine fortsetzbare Pipeline muss pro Dokument wissen, was festgeschrieben wurde und was nicht, bevor der Absturz eintrat — was genau das ist, wozu die Checkpoint- und Idempotenz-Speicher existieren.
Grenzen und Abgrenzungen
Abschnitt betitelt „Grenzen und Abgrenzungen“- Jede Signatur ist pro Dokument und standardgebunden; es gibt keine Stapelabkürzung. Volumen ändert die Ablaufplanung, nicht die kryptografische Einheit. NextPDF signiert jedes Dokument über seinen eigenen Byte-Bereich.
- Core leistet software-basiertes CMS-Signieren und PAdES B-B (B-T über einen Zeitstempel-Client). Die dauerhafte, nebenläufige, exactly-once Render-und-Signier-Engine ist das Stream-Modul in den erweiterten Editionen; HSM/KMS-gestützte Schlüsselverwahrung ist eine Nahtstelle der erweiterten Editionen. Diese Seite beansprucht diese Orchestrierung nicht als Core.
- Fail-closed ist das Verhalten der Engine, keine Garantie über Ihre
Verdrahtung. NextPDF weigert sich, eine unsignierte-aber-für-signiert-gehaltene
Datei auszugeben, und legt den unterstützten Signierweg offen. Eine Pipeline,
die den daraus entstehenden Fehler abfängt und trotzdem festschreibt, hat sich
entschieden, die Garantie zu durchbrechen — die Rahmung, die das
catch/continuedes Beispiels zu verhindern existiert. - Die PAdES-Stufe wird pro Dokument durchgesetzt, nicht für den Lauf zertifiziert. Die Engine erzeugt die verlangte Baseline-Stufe oder scheitert; das ist eine strukturelle Durchsetzung, kein Konformitätsurteil eines Dritten für die erzeugten Dateien. Die Stufenabfolge selbst wird behandelt in PAdES-Baseline-Profile.
- Die Warteschlange, die Schlüsselverwahrung, die Zeitstempelinstanz und der Objektspeicher gehören Ihnen. NextPDF liefert die Signier-Korrektheit pro Dokument und, in den erweiterten Editionen, die dauerhaften Orchestrierungsprimitive. Es betreibt nicht Ihre Infrastruktur und bürgt nicht für Ihre TSA.
| Edition | Availability |
|---|---|
| Core | Software-basiertes CMS-Signieren pro Dokument, PAdES B-B (B-T mit einem Zeitstempel-Client), einzeln über den eigenen Byte-Bereich jedes Dokuments signiert, fail-closed gegen stillschweigend unsignierte Ausgabe. Einfaches Signieren pro Dokument benötigt keine kommerzielle Edition. |
| Pro | Ergänzt das Stream-Modul: eine seiteneffektfreie Render-Engine plus dauerhafte Committer-, Checkpoint-, Idempotenz- und Dead-Letter-Speicher — nebenläufige, absturzsichere, exactly-once Stapelläufe, die fortsetzen statt neu zu starten. |
| Enterprise | Ergänzt hardwaregestützte Schlüsselverwahrung (HSM über PKCS#11 oder ein Cloud-KMS), sodass der private Schlüssel das Gerät nie verlässt, sowie die langfristigen PAdES-Stufen (B-LT, B-LTA), die ein Archiv in großer Zahl über Jahrzehnte verifizierbar halten. |
Verwandte Dokumente
Abschnitt betitelt „Verwandte Dokumente“- Dokumentenerzeugung in großer Zahl — das speicherbegrenzte, in die Warteschlange gestellte Stapelmodell, auf dem diese Seite das Signieren aufsetzt; lesen Sie es zuerst für die Disziplin von Durchsatz und Messung.
- PAdES-Baseline-Profile — was jede Stufe (B-B bis B-LTA) hinzufügt, damit Sie auf der Stufe signieren, die die Verpflichtung verlangt.
- Wie Signaturen in einem PDF sitzen — die Byte-Range- und Dictionary-Grundlage, die eine Signatur pro Dokument macht.
- HSM-gestütztes Signieren — wo die Grenze zum privaten Schlüssel verläuft, wenn das Signiermaterial in Hardware lebt.
- Stream (Pro) — die dauerhafte, nebenläufige, exactly-once Render-Engine, die eine einzelne Signiereinheit in einen fortsetzbaren Lauf verwandelt.
Glossar
Abschnitt betitelt „Glossar“- Stapelsignieren — viele Dokumente nach einem Zeitplan signieren. Ein Konzept der Ablaufplanung; jedes Dokument wird weiterhin einzeln über seine eigenen Bytes signiert.
- Fail-closed — bei einem Versagen, das andernfalls eine unsignierte oder falsche Ausgabe erzeugen würde, hält die Pipeline das Dokument zurück und meldet, statt es als bloße Bytes weiterzugeben.
- Exactly-once-Commit — eine Eigenschaft dauerhafter Pipelines, bei der eine korrekt signierte Ausgabe einmal veröffentlicht und nicht erneut ausgegeben wird, wenn ein abgestürzter Lauf fortsetzt.
- Checkpoint — dauerhafter Datensatz pro Dokument darüber, was festgeschrieben wurde, sodass ein Lauf von der Stelle fortsetzen kann, an der er aufhörte, statt alles neu zu signieren.
- CMS SignedData — der kryptografische Behälter für Signaturen über Inhalt (er kann mehrere Signierende tragen); diese Pipeline erzeugt die PDF-Signatur eines Signierenden pro Dokument, die Einheit pro Dokument, die ein Stapel erzeugt.
- PAdES — PDF Advanced Electronic Signatures, die ETSI-EN-319-142-Profilfamilie zum PDF-Signieren; ihre Baseline-Stufen reichen von B-B bis B-LTA.