Contracts / Signatur
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Die Signing-Domain umfasst sechs Contracts. Sie definieren, wie Sie eine CMS-Signatur erzeugen, einen RFC 3161-Zeitstempel anwenden, mit einem Hardware-Schlüssel signieren und die Langzeitvalidierung aktivieren. Core veröffentlicht die Contracts; die Pro- und Enterprise-Editionen liefern den Produktivcode.
Installation
Abschnitt betitelt „Installation“composer require nextpdf/core:^3Konzeptioneller Überblick
Abschnitt betitelt „Konzeptioneller Überblick“Eine digitale PDF-Signatur ist eine CMS-SignedData-Struktur, die im Signatur-Dictionary gespeichert wird. Der Eintrag Contents enthält die DER-codierte Struktur. Der Eintrag ByteRange benennt die Byte-Bereiche, die der Digest abdeckt. Der Digest umfasst die gesamte Datei und schließt den Signaturwert selbst aus; siehe ISO 32000-2 §12.8.1. Die CMS-Struktur folgt RFC 5652 §5.1: einer Sequenz aus Version, Digest-Algorithmen, eingekapseltem Inhalt und Signer-Information.
SignerInterface ist der zentrale Contract. Er erzeugt die CMS-SignedData für einen Byte-Bereich, versieht einen Signaturwert mit einem Zeitstempel und meldet, ob er Langzeitvalidierung unterstützt. Er bildet die PAdES-Baseline-Stufen B-B bis B-LTA ab, wie in ETSI EN 319 142 definiert. Jede höhere Stufe ergänzt weiteres Material. B-B enthält die Basis-Signatur. B-T ergänzt einen Signatur-Zeitstempel. B-LT ergänzt Sperrdaten. B-LTA ergänzt einen Archiv-Zeitstempel.
HsmSignerInterface signiert mit einem Schlüssel, der in einem Hardware-Security-Modul gespeichert ist. Der private Schlüssel verlässt die Hardwaregrenze nicht. Der Contract gibt das Signer-Zertifikat und die Zertifikatskette in DER-Form zurück, damit die CMS-Schicht die Struktur aufbauen kann. DeferredSignerInterface erweitert SignerInterface für asynchrones Signieren. Der Aufrufer übermittelt Daten, erhält eine Job-Kennung, fragt den Abschluss ab und ruft anschließend das Ergebnis ab. Verwenden Sie ihn, wenn ein entferntes HSM oder ein Cloud-Schlüsseldienst nicht sofort ein Ergebnis zurückgibt.
TimestampProviderInterface fordert ein RFC 3161-Zeitstempel-Token an. Das Protokoll besteht aus einer Anfrage und einer Antwort, die mit einer Time-Stamping Authority ausgetauscht werden; siehe RFC 3161 §2.4. Der messageImprint im Token ist ein Hash des Signaturwerts; RFC 3161 §2.4.2. LtvManagerInterface aktiviert die Langzeitvalidierung. Er sammelt die Zertifikatskette, holt OCSP- und CRL-Antworten ein, baut den Document Security Store auf und fügt einen Dokument-Zeitstempel für B-LTA hinzu. CryptoPolicyInterface steuert, welche Hash-, Signatur- und Verschlüsselungsalgorithmen sowie welche Schlüsselstärken erlaubt sind, bevor eine kryptografische Operation ausgeführt wird.
API-Oberfläche
Abschnitt betitelt „API-Oberfläche“| Typ | Art | Zentrale Mitglieder | Stabilität | Seit |
|---|---|---|---|---|
SignerInterface | interface | sign(string): SignatureResult, timestamp(string): string, supportsLtv(): bool | stable | 1.0.0 |
HsmSignerInterface | interface | sign(string, string): string, getCertificateDer(), getCertificateChainDer(), getPublicKeyAlgorithm() | stable | 1.0.0 |
DeferredSignerInterface | interface | submitForSigning(string): string, retrieveSignature(string), isComplete(string) (erweitert SignerInterface) | experimental | 3.0.0 |
TimestampProviderInterface | interface | getTimestamp(string): string | experimental | 3.0.0 |
LtvManagerInterface | interface | enableLtv(...), addDocumentTimestamp(...) | stable | 1.10.0 |
CryptoPolicyInterface | interface | isHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName() | stable | 1.9.0 |
SignerInterface::sign() gibt ein NextPDF\Security\Signature\SignatureResult zurück. Die öffentliche Eigenschaft $cmsSignedData enthält das DER-codierte CMS. Die öffentliche Eigenschaft $digestHex enthält den SHA-256-Digest. Die öffentliche Eigenschaft $timestampToken enthält das optionale TSA-Token. Die Accessoren sind toHex() / toHexPadded(int) / getSize() / hasTimestamp(). HsmSignerInterface::sign() gibt DER-codierte Bytes für RSA und rohe r‖s-Bytes für ECDSA zurück. Das Algorithmusargument verwendet OpenSSL-Bezeichner.
Codebeispiel — Schnellstart
Abschnitt betitelt „Codebeispiel — Schnellstart“<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/** * Sign a byte range with any SignerInterface implementation. * * @param SignerInterface $signer A core or Premium signer. * @param string $byteRange The PDF byte range to sign. * * @return string Hex-encoded CMS SignedData for the PDF /Contents field. */function signByteRange(SignerInterface $signer, string $byteRange): string{ $result = $signer->sign($byteRange);
return $result->toHex();}SignerInterface::sign() gibt ein SignatureResult zurück. toHex() gibt die Hex-Zeichenkette zurück, die der Writer in das Feld /Contents einsetzt; die rohen DER-Bytes liegen in der öffentlichen Eigenschaft $cmsSignedData. Die Funktion hängt vom Contract ab, nicht von einer konkreten Klasse. Sowohl ein Core-Test-Signer als auch ein Premium-HSM-Signer erfüllen ihn.
Codebeispiel — Produktion
Abschnitt betitelt „Codebeispiel — Produktion“<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;use NextPDF\Contracts\SignerInterface;use NextPDF\Contracts\TimestampProviderInterface;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final readonly class TimestampedSigningService{ public function __construct( private SignerInterface $signer, private TimestampProviderInterface $timestamps, private CryptoPolicyInterface $policy, private LoggerInterface $logger, ) {}
/** * Sign a byte range, then timestamp the CMS structure. * * @param string $byteRange The PDF byte range to sign. * * @return array{cms: string, digest: string, tst: string} */ public function sign(string $byteRange): array { if (!$this->policy->isHashAlgorithmAllowed($this->policy->getPreferredHashAlgorithm())) { throw new \LogicException('Preferred hash rejected by crypto policy.'); }
try { $signature = $this->signer->sign($byteRange); $token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return [ 'cms' => $signature->toHex(), 'digest' => $signature->digestHex, 'tst' => $token, ]; } catch (NextPdfException $e) { $this->logger->error('Signing failed', [ 'policy' => $this->policy->getName(), 'error' => $e->getMessage(), ]);
throw $e; } }}Der Dienst injiziert drei Contracts. Die Crypto-Policy wird vor der Signieroperation konsultiert. SignatureResult stellt die CMS-Bytes in der öffentlichen Eigenschaft $cmsSignedData bereit, den SHA-256-Digest in $digestHex sowie toHex() für die Hex-Zeichenkette von /Contents. Der Timestamp-Provider erhält die CMS-Bytes und gibt ein DER-codiertes Token zurück. Der Catch-Block protokolliert den Policy-Namen und wirft die Ausnahme erneut. Er verschluckt den Fehler nie.
Edge Cases & Stolperfallen
Abschnitt betitelt „Edge Cases & Stolperfallen“- Der Byte-Bereichs-Digest muss den Signaturwert ausschließen. Ein Digest, der den Eintrag
Contentsabdeckt, erzeugt eine Signatur, die sich niemals verifizieren lässt; ISO 32000-2 §12.8.1. SignerInterface::supportsLtv()meldet die Fähigkeit, nicht den Zustand. Ein Signer kann die Langzeitvalidierung unterstützen und trotzdem eine B-B-Signatur erzeugen, wenn kein Zeitstempeldienst konfiguriert ist.DeferredSignerInterface::retrieveSignature()liefertnull, bis der Job abgeschlossen ist. Fragen Sie zuerstisComplete()ab, um nicht bei jeder Prüfung die Nutzlast zu übertragen. Der Abruf ist idempotent, sobald ein Ergebnis vorliegt.LtvManagerInterface::addDocumentTimestamp()muss ausgeführt werden, nachdem der Document Security Store geschrieben wurde. Wird sie zuerst aufgerufen, entsteht eine ungültige B-LTA-Struktur.CryptoPolicyInterfacelieferttruefür jeden Algorithmus, wenn keine Policy gesetzt ist. Setzen Sie in einer regulierten Umgebung eine explizite Policy; verlassen Sie sich nicht auf den offenen Standardwert.HsmSignerInterface::getCertificateChainDer()schließt das Signer-Zertifikat aus. Verwenden SiegetCertificateDer()für das Signer-Blattzertifikat und die Kettenmethode für die Zwischenzertifikate.
Performance
Abschnitt betitelt „Performance“Die Signierkosten werden von der kryptografischen Operation und einem etwaigen Netzwerk-Roundtrip dominiert, nicht vom Contract. Eine lokale Software-Signatur liegt im einstelligen Millisekundenbereich. Eine HSM-Signatur fügt den Geräte-Roundtrip hinzu. Ein Zeitstempel fügt einen Netzwerk-Roundtrip zur Time-Stamping Authority hinzu. Die Langzeitvalidierung fügt einen OCSP- oder CRL-Abruf pro Zertifikat in der Kette hinzu. Das performance_budget von 1500 ms Wall-Time deckt eine einzelne zeitgestempelte Signatur mit einer entfernten TSA bei warmer Verbindung ab. Eine Langzeitvalidierung über einen langsamen Sperr-Endpunkt überschreitet es und sollte außerhalb des Request-Pfads laufen. Das Reproduzierbarkeitsprofil ist structural, nicht bitwise. Ein Zeitstempel bettet den Signaturzeitpunkt ein, sodass sich zwei Läufe in den Zeitstempel-Bytes unterscheiden, während die Dokumentstruktur identisch bleibt.
Sicherheitshinweise
Abschnitt betitelt „Sicherheitshinweise“Die Signing-Contracts sind die primäre kryptografische Grenze der Engine; deshalb ist das Bedrohungsmodell explizit. Die Schlüsselverwahrung ist das erste Anliegen: HsmSignerInterface hält den privaten Schlüssel innerhalb der Hardwaregrenze, und der Contract gibt nie Schlüsselmaterial preis. Algorithmus-Downgrades sind das zweite Anliegen: CryptoPolicyInterface blockiert schwache Hashes und kurze Schlüssel vor der Operation, sodass ein Deployment ein FIPS 140-3- oder eIDAS-Profil ohne Fork der Engine durchsetzen kann. Das Vertrauen in Zeitstempel ist das dritte Anliegen: Ein RFC 3161-Token ist nur so vertrauenswürdig wie die Time-Stamping Authority, daher ist der Provider-Contract injizierbar, und ein Deployment legt seine eigene Authority fest. Die Langzeitvalidierung ist das vierte Anliegen: Sperrmaterial wird zum Signierzeitpunkt geholt und im Document Security Store abgelegt, sodass die Verifikation den Ablauf des Zertifikats überdauert. Behandeln Sie jede Signer-Eingabe als nicht vertrauenswürdig. Der Byte-Bereich wird von der Engine berechnet, nie vom Aufrufer übernommen. Diese Seite ist mit export_control_class: legal-review-required markiert, weil die Contracts das kryptografische Signieren steuern. Die Prosa paraphrasiert alle normativen Quellen und zitiert keine davon, entsprechend der Zitierhygiene.
Konformität
Abschnitt betitelt „Konformität“| Aussage | Standard | Abschnitt | Nachweis |
|---|---|---|---|
Der Signaturwert wird DER-codiert im Eintrag Contents des Signatur-Dictionarys gespeichert, als CMS SignedData oder als TimeStampToken. | ISO 32000-2 | §12.8.1 | |
Der Digest wird über den Byte-Bereich berechnet, der durch das Array ByteRange definiert ist, und schließt den Signaturwert aus. | ISO 32000-2 | §12.8.1 | , |
| Langzeitvalidierungsmaterial wird im Document Security Store mit VRI-, OCSP-, CRL- und Zertifikatseinträgen geführt. | ISO 32000-2 | §12.8.4.3 | , |
| Die PAdES-Langzeitvalidierung legt Validierungsdaten in den DSS- und VRI-Dictionarys ab. | ETSI EN 319 142-2 | §6.3 | , |
Ein RFC 3161-Zeitstempel-Token bindet über messageImprint einen Hash des Signaturwerts; der Austausch erfolgt über eine TSA-Anfrage und -Antwort. | RFC 3161 | §2.4.2, §2.4 | , |
| Die CMS-SignedData-Sequenz trägt Version, Digest-Algorithmen, eingekapselten Inhalt und Signer-Information. | RFC 5652 | §5.1 |
Alle Klauseln sind paraphrasiert. NextPDF gibt keinen normativen Text wieder. Konsultieren Sie die veröffentlichten Standards für den maßgeblichen Wortlaut.
Kommerzieller Kontext
Abschnitt betitelt „Kommerzieller Kontext“Core veröffentlicht die Signing-Contracts und friert sie ein. Die Produktivimplementierungen hinter HsmSignerInterface, LtvManagerInterface und dem Deferred-Signer werden in den Pro- und Enterprise-Editionen ausgeliefert, einschließlich PKCS#11-Hardware-Integration sowie PAdES B-LT und B-LTA. Core löst sie zur Laufzeit mit class_exists() auf und castet auf den Contract, sodass die Open-Source-Engine keine kommerzielle Abhängigkeit trägt und sich die API beim Upgrade nicht ändert.
Siehe auch
Abschnitt betitelt „Siehe auch“- Contracts: 41 öffentliche Interfaces (SPI) — der SPI-Überblick und die Stabilitätsstufen.
- Contracts / Security Policy —
CryptoPolicyInterfacefür Algorithmus- und Schlüssel-Gating. - Contracts / Extraction — PDF/A-Durchsetzung, die zur signierten Archivierung passt.
- Security — Implementierungsoberfläche für Verschlüsselung und Signatur.
- Audit — Audit-Logging für Policy-Namen und Signier-Events.
- Exception — die von Signern geworfene
NextPdfException-Hierarchie.