Zum Inhalt springen
getnextpdf.com

Enterprise Edition

HSM-Signierung — Ausführliche Referenz

Diese Seite ist die ausführliche Referenz für die HSM-Signierschnittstelle von NextPDF Enterprise. Sie behandelt drei öffentliche Typen. NextPDF\Enterprise\Security\Signature\Hsm\Pkcs11Signer signiert über ein PKCS#11-Token mittels der ext-pkcs11-Erweiterung. NextPDF\Enterprise\Security\Signature\Hsm\OpenSslCliSigner signiert über die openssl-Binärdatei in einem Subprozess, für Provider- oder Engine-gestützte Schlüssel, die PHP ext-openssl nicht laden kann. NextPDF\Enterprise\Security\Signature\Hsm\Provider\HsmSignerProviderAdapter stellt jede der beiden Konkretisierungen als einheitliches SignerProviderInterface bereit. In jedem Pfad bleibt der private Schlüssel innerhalb der Token-Grenze; NextPDF übergibt die zu signierenden Bytes und erhält die Signatur zurück. Der Post-Quantum-Pfad (signPqs) ist eine Vorschau: er ist standardmäßig deaktiviert, trägt keinen Konformitätsanspruch und hat in aktuellen PDF-Validatoren keinen unterstützten Verifikationspfad. NextPDF besitzt keine Zertifizierung und gewährt keine; Unterstützung ist nicht gleich Konformität, und Konformität ist nicht gleich Zertifizierung.

Diese Fähigkeit wird mit NextPDF Enterprise (nextpdf/enterprise) ausgeliefert und aktiviert sich mit einem Lizenz-Envelope der Enterprise-Stufe. Eine Bereitstellung ohne diese Berechtigung lädt die Klassen der Fähigkeit nicht. Editionen vergleichen und eine Lizenz erwerben.

Alle drei Typen liegen in NextPDF\Enterprise\Security\Signature\Hsm; der Adapter befindet sich in dessen Provider-Unter-Namespace. Beide Signierer implementieren den Core-Vertrag NextPDF\Contracts\HsmSignerInterface.

SymbolParameterStandardverhaltenRückgabeWirft oder scheitert mitHinweise
Pkcs11Signer::__construct()string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = nullÖffnet die Hersteller-Library, meldet sich am Slot an und lädt das Zertifikat sowie die Schlüsselalgorithmus-Metadaten vom TokenHsmOperationException, wenn ext-pkcs11 fehlt oder der Token-Zugriff scheitertEin Modul-Handle wird pro Library-Pfad pro Prozess zwischengespeichert; PIN und Labels sind #[SensitiveParameter]
Pkcs11Signer::sign()string $data, string $algorithm = 'sha256WithRSAEncryption'Signiert auf dem Token; die rohe ECDSA-Ausgabe wird in DER ECDSA-Sig-Value konvertiertstring rohe SignaturbytesHsmOperationException (Schlüssel nicht gefunden, Token-Ausfall); InvalidArgumentException (nicht zugeordneter Algorithmus); FIPS-Gate-Ausnahmen vor dem Signieren, wenn ein Enforcer verdrahtet istGeschlossene Algorithmusmenge; siehe Verhaltensvertrag
Pkcs11Signer::signPqs()string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = trueVerweigert, sofern $enablePostQuantum nicht gesetzt wurde; ruft den provisorischen PKCS#11-PQ-Mechanismus aufstring rohe SignaturbytesHsmOperationException (deaktiviert, Token-Ausfall, Signaturlängen-Diskrepanz); InvalidArgumentException (Kontext über 255 Bytes)Vorschau; kein Konformitätsanspruch; Mechanismus-Identifikatoren sind provisorisch
Pkcs11Signer::isPostQuantumEnabled()KeineMeldet das Opt-in-Flag des KonstruktorsboolKeine
Pkcs11Signer::getCertificateDer()KeineGibt das vom Token gelesene Signierzertifikat zurückstring (DER)KeineWird einmal bei der Konstruktion geladen
Pkcs11Signer::getCertificateChainDer()KeineGibt die vom Konstruktor gelieferten Zwischenzertifikate zurückarray<string> (DER)KeineSchließt das Signierzertifikat aus
OpenSslCliSigner::__construct()string $keyUri, string $certPath, string $pin, array $extraCertPaths = [], OpenSslCliBackend $backend = OpenSslCliBackend::Auto, string $opensslBinary = 'openssl', int $timeoutSeconds = 30, ?string $modulePath = null, ?string $configPath = null, bool $legacyPinDelivery = false, ?FipsSignatureEnforcer $fipsEnforcer = nullVerifiziert proc_open, prüft die Binärdatei und Version, ermittelt das Backend und lädt die ZertifikateHsmOperationException (proc_open deaktiviert, fehlende Modul-/Konfig-/Zertifikatsdatei, Binär-Ausfall, kein Backend); InvalidArgumentException (pin-value innerhalb $keyUri)OpenSslCliBackend::Auto bevorzugt den OpenSSL-3.x-Provider, dann die Engine
OpenSslCliSigner::sign()string $data, string $algorithm = 'sha256WithRSAEncryption'Führt openssl dgst in einem Subprozess aus; die PIN wandert standardmäßig durch eine ephemere 0600-pin-source-Dateistring rohe SignaturbytesHsmOperationException (Timeout, PIN abgelehnt, Schlüssel nicht gefunden, Modul-Ladefehler, leere Ausgabe, pin-file-Fehler); InvalidArgumentException (nicht zugeordneter Algorithmus); FIPS-Gate-Ausnahmen vor dem SignierenDer Subprozess wird nach $timeoutSeconds beendet; stderr wird redigiert, bevor es in Meldungen gelangt
OpenSslCliSigner-Accessor-OberflächeKeineSchreibgeschützte Konstruktionsergebnissestring / array<string> / OpenSslCliBackendKeinegetCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion
HsmSignerProviderAdapter::__construct()HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15Umschließt eine HSM-Konkretisierung als SignerProviderInterfaceKeineProvider-ID-Konventionen: pkcs11-{module-id}, openssl-cli
HsmSignerProviderAdapter::providerId()KeineGibt die vom Konstruktor gelieferte ID zurücknon-empty-stringKeine
HsmSignerProviderAdapter::supportsAlgorithm()SignatureAlgorithm $algoOrdnet das Enum einem Namen im OpenSSL-Stil zu und schneidet es dann mit der Backend-ZulassungsmengeboolKeineLehnt reine Digest-Algorithmen ab; openssl-engine-IDs bewerben nichts
HsmSignerProviderAdapter::sign()string $data, ?string $keyVersion = nullReicht über den umschlossenen Signierer mit dem konfigurierten Algorithmus weiternon-empty-stringKeyManagementException (nicht-null $keyVersion); SignatureFailedException (nicht zuordenbarer Algorithmus, Treiber-Ausfall, leere Signatur)Fail-closed-SPI-Vertrag; jeder Treiberfehler tritt typisiert zutage
public function __construct(private readonly string $libraryPath, private readonly int $slotId, #[SensitiveParameter] private readonly string $pin, #[SensitiveParameter] private readonly string $certLabel, #[SensitiveParameter] private readonly ?string $keyLabel = null, array $chainDer = [], private readonly bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = null)
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
public function signPqs(string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true): string
public function isPostQuantumEnabled(): bool
public function getCertificateDer(): string
public function getCertificateChainDer(): array
public function __construct(private string $keyUri, string $certPath, #[SensitiveParameter] private string $pin, array $extraCertPaths = [], private OpenSslCliBackend $backend = OpenSslCliBackend::Auto, private string $opensslBinary = 'openssl', private int $timeoutSeconds = 30, private ?string $modulePath = null, private ?string $configPath = null, private bool $legacyPinDelivery = false, private ?FipsSignatureEnforcer $fipsEnforcer = null)
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
public function getCertificateDer(): string
public function getCertificateChainDer(): array
public function getPublicKeyAlgorithm(): string
public function getCertificatePem(): string
public function getResolvedBackend(): OpenSslCliBackend
public function getOpensslVersion(): string
public function __construct(private HsmSignerInterface $hsm, private string $providerId, private SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15)
public function providerId(): string
public function supportsAlgorithm(SignatureAlgorithm $algo): bool
public function sign(string $data, ?string $keyVersion = null): string
  • Schlüsselverwahrung. Der private Schlüssel verlässt niemals die Token-Grenze. Pkcs11Signer delegiert die Operation an das Token; OpenSslCliSigner übergibt eine Schlüssel-Referenz — eine PKCS#11-URI — an den openssl-Subprozess. Keiner der Signierer kann den Schlüssel exportieren.
  • Sitzung und Anmeldung. Pkcs11Signer speichert ein PKCS#11-Modul-Handle pro Library-Pfad pro Prozess zwischen, da die Token-Schnittstelle genau einmal pro Prozess initialisiert werden muss. Jede Operation öffnet eine Sitzung und meldet sich mit der PIN an; die Anmeldung authentifiziert den Benutzer vor jeder Nutzung des privaten Schlüssels (PKCS#11 v3.1 §5.6.8). Wenn der Slot eine bestehende Anmeldung meldet, meldet sich der Signierer ab und erneut an, sodass Tokens, die pro Operation eine frische PIN verlangen, eine solche erhalten.
  • Algorithmusmenge (geschlossen). Beide Signierer akzeptieren genau: sha256WithRSAEncryption, sha384WithRSAEncryption, sha512WithRSAEncryption; RSASSA-PSS, RSASSA-PSS-SHA256, RSASSA-PSS-SHA384, RSASSA-PSS-SHA512; ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512. Pkcs11Signer akzeptiert zusätzlich ecdsa-raw. Jeder andere Identifikator löst InvalidArgumentException aus — es wird niemals ein Ersatzalgorithmus signiert.
  • PSS-Salt-Bindung. Für jede PSS-Variante entspricht die Salt-Länge der Digest-Länge — 32, 48 oder 64 Bytes — und die Hash- und MGF-Parameter passen zum gewählten Digest. Dies folgt der PSS-Mechanismus-Parameterstruktur, in der die Salt-Länge typischerweise die Länge des Nachrichten-Hashs ist (PKCS#11 v3.1 §6.1.9). Beide Signierer wenden dieselbe Paarung an, sodass eine auf einem Backend gültige Konfiguration auch auf dem anderen gültig ist.
  • ECDSA-Konvertierung. Ein Token gibt eine ECDSA-Signatur als rohe, mit Nullen aufgefüllte Verkettung von r und s zurück (PKCS#11 v3.1 §6.3.1). Pkcs11Signer::sign() konvertiert diese Ausgabe in die DER-kodierte ECDSA-Sig-Value-Form, die PDF-Validatoren und OpenSSL erwarten. Der Aufrufer verarbeitet niemals die rohe Form.
  • PIN-Übergabe (CLI-Pfad). Im sicheren Standard wird die PIN in eine ephemere Datei geschrieben, die exklusiv mit Nur-Eigentümer-Berechtigungen erstellt wird, über das PKCS#11-URI-Attribut pin-source referenziert und nach Beendigung des Subprozesses entfernt (unlink). Die PIN wird in diesem Modus nicht in die Befehlszeile gestellt und nicht in die Subprozess-Umgebung exportiert. Mit $legacyPinDelivery = true wird die PIN als pin-value in die URI eingebettet, was in der Prozess-Befehlszeile beobachtbar ist; dieser Modus ist ausschließlich Opt-in.
  • Subprozess-Disziplin. OpenSslCliSigner startet die Binärdatei mit einem Argument-Array — keine Shell-Interpolation —, erzwingt $timeoutSeconds, beendet den Subprozess bei Ablauf und klassifiziert stderr in typisierte Fehler. Geheimnisse werden aus stderr redigiert, bevor es in einer Ausnahmemeldung zitiert wird.
  • Adapter-Semantik. Ein HSM-Token hat kein verwaltetes Schlüsselversions-Konzept; der Schlüssel auf dem Token ist die Version. HsmSignerProviderAdapter::sign() weist daher jede nicht-null $keyVersion mit KeyManagementException zurück, anstatt sie zu ignorieren. supportsAlgorithm() schneidet die Enum-Zuordnung mit der akzeptierten Menge des umschlossenen Backends, sodass der Adapter niemals einen Mechanismus bewirbt, den das Backend zur Signierzeit ablehnen würde. Eine leere Signatur vom Treiber löst SignatureFailedException aus.
  • Post-Quantum-Vorschau. signPqs() ist hinter das Konstruktor-Flag $enablePostQuantum gestellt und verweigert andernfalls die Ausführung. Die Kontextzeichenkette ist auf 255 Bytes begrenzt, passend zur ML-DSA-Kontextgrenze (FIPS 204). Die zurückgegebene Signatur muss der exakten Byte-Länge des gewählten Pkcs11PqsAlgorithm-Parametersatzes entsprechen, sonst schlägt der Aufruf fehl. Die Mechanismus-Identifikatoren folgen einer provisorischen PKCS#11-PQ-Erweiterung und sind nicht endgültig. PAdES-Profile erkennen keine Post-Quantum-Suites, die meisten PDF-Validatoren lehnen solche Signaturen ab, und NextPDF stellt keinen Verifikationspfad für sie bereit. Es wird keine Konformität beansprucht.
  • Die Konstruktion von Pkcs11Signer ohne ext-pkcs11 löst sofort HsmOperationException aus; die Erweiterung ist nicht in den Standard-PHP-Distributionen enthalten.
  • Ein Zertifikats- oder Privatschlüssel-Label, das keinem Objekt auf dem Token entspricht, löst HsmOperationException aus und benennt die fehlende Objektklasse. Das Schlüssel-Label darf auf manchen Tokens legitim vom Zertifikats-Label abweichen.
  • Wiederholt fehlgeschlagene Anmeldungen können die PIN am Token sperren; das Token erzwingt diese Richtlinie, nicht NextPDF. Tokens, deren Schlüssel bei jeder Nutzung eine Authentifizierung erfordern, erhalten über den Abmelde-und-erneut-Versuch-Pfad eine frische Anmeldung (PKCS#11 v3.1, Always-authenticate-Semantik).
  • OpenSslCliSigner verweigert bei der Konstruktion fail-closed eine $keyUri, die bereits pin-value enthält, da diese Übergabe den sicheren PIN-Pfad umgehen würde.
  • Unter Windows schlägt der sichere pin-file-Modus mit HsmOperationException fail-closed fehl: Dateiberechtigungsbits können dort ACL-Lesegewährungen nicht einschränken, sodass der Signierer sich weigert, eine Klartext-PIN in der ACL des Temp-Verzeichnisses zu hinterlassen. Die Legacy-PIN-Übergabe ist die dokumentierte Opt-in-Alternative für vertrauenswürdige Windows-Hosts.
  • Die automatische Backend-Erkennung erfordert OpenSSL 3.x für den Provider-Pfad; LibreSSL löst niemals zum Provider auf. Wenn weder eine Provider- noch eine Engine-Prüfung erfolgreich ist, schlägt die Konstruktion mit HsmOperationException fehl, anstatt den Fehler auf die Signierzeit zu verschieben.
  • Ein Subprozess, der $timeoutSeconds überschreitet, wird beendet und als Timeout gemeldet; ein Subprozess, der sauber mit leerer Ausgabe endet, wird als Fehler „leere Signatur“ gemeldet. Keine der beiden Bedingungen kann ein teilweise signiertes Dokument erzeugen.
  • Eine Post-Quantum-Signatur, deren Byte-Länge nicht zum gewählten Parametersatz passt, wird abgewiesen, bevor sie die CMS-Kodierung erreichen kann.
  • HsmSignerProviderAdapter mit der ausgemusterten Provider-ID openssl-engine bewirbt keine Algorithmen, sodass eine veraltete Konfiguration bei der Provider-Auswahl statt zur Signierzeit fehlschlägt.

Beide Signierer akzeptieren einen optionalen FipsSignatureEnforcer. Ist einer verdrahtet, ist der FIPS-Modus für diesen Signierer aktiv: sign() weist einen unzulässigen Signaturalgorithmus oder einen Schlüssel unterhalb der Untergrenze vor jeder Token- oder Subprozess-Signierung zurück. Die Untergrenzen folgen der Tabelle zur Signaturerzeugung — RSA-Moduli unter 2048 Bit und ECDSA-Ordnungen unter 224 Bit sind unzulässig (NIST SP 800-131A Rev.2 §3 Table 2). Ohne Enforcer bleibt das Verhalten unverändert. Das Gate deckt nur den klassischen sign()-Pfad ab; signPqs() unterliegt seinem eigenen Vorschau-Flag. Dies sind Fähigkeitsaussagen über NextPDF-Code: Die FIPS-140-3-Validierung heftet sich über die CMVP an ein kryptografisches Modul, das in dieser Bereitstellung das HSM oder der Provider des Betreibers ist — NextPDF ist kein validiertes Modul, besitzt keine Zertifizierung und gewährt keine.

AnspruchStandardKlausel
Die Anmeldung authentifiziert den Benutzer vor Operationen mit dem privaten Schlüssel am Token; eine falsche PIN verweigert den Zugriff.PKCS#11 v3.1§5.6.8
Always-authenticate-Schlüssel benötigen eine frische Anmeldung pro Nutzung; wiederholt fehlgeschlagene Re-Authentifizierung kann die PIN sperren.PKCS#11 v3.1CKA_ALWAYS_AUTHENTICATE re-authentication
Eine Token-ECDSA-Signatur ist die rohe r‖s-Verkettung; der Signierer konvertiert sie für die PDF-Interoperabilität in DER.PKCS#11 v3.1§6.3.1
PSS-Parameter binden Hash, MGF und Salt-Länge; die Signierer setzen das Salt gleich der Digest-Länge.PKCS#11 v3.1§6.1.9
Das FIPS-Gate verweigert die Signaturerzeugung mit RSA unter 2048 Bit oder ECDSA-Ordnung unter 224 Bit.NIST SP 800-131A Rev.2§3 Table 2
Die Post-Quantum-Kontextzeichenkette ist auf 255 Bytes begrenzt.FIPS 204HashML-DSA context handling
Die FIPS-140-3-Validierung heftet sich über die CMVP an kryptografische Module.FIPS 140-3CMVP program scope

Alle Klauseln sind paraphrasiert; kein normativer Text wird wiedergegeben. NextPDF erhebt keinen Zertifizierungsanspruch. Die Signierer richten ihr Verhalten als Fähigkeit an den zitierten Klauseln aus. Ob eine erzeugte Signatur verifiziert, ist die Entscheidung des Verifizierers gegen seine Vertrauensanker; die Schlüsselsicherheit hängt vom Token, vom HSM und vom Betreiber ab — nicht von NextPDF allein.

  • Der PIN-Übergabemechanismus folgt der PKCS#11-URI-Konvention pin-source (RFC 7512); dieser RFC liegt außerhalb des zitierten Korpus, sodass das obige Verhalten aus der Produktquelle abgeleitet ist, nicht aus einer Spezifikationszitierung.

  • Stellen Sie sicher, dass die Laufzeit ext-pkcs11 lädt, bevor Sie Pkcs11Signer konstruieren; die Konstruktion schlägt schnell fehl, wenn die Erweiterung fehlt. Der CLI-Signierer benötigt aktiviertes proc_open und eine openssl-Binärdatei mit installiertem PKCS#11-Provider oder -Engine.

  • Die PIN, das Zertifikats-Label und das Schlüssel-Label sind #[SensitiveParameter], sodass sie aus Stacktraces ausgeschlossen werden. Liefern Sie die PIN aus einem Secret-Manager; schreiben Sie sie niemals in Quellcode, in unter Versionskontrolle eingecheckte Konfiguration oder in Logs.

  • Die Konstruktion ist bei beiden Signierern der teure Schritt: Der PKCS#11-Pfad meldet sich an und liest das Zertifikat, und der CLI-Pfad prüft Binärdatei und Backend. Konstruieren Sie einmal und verwenden Sie die Instanz wieder; der Modul-Cache pro Library macht wiederholte Konstruktion gegen dieselbe Library sicher.

  • Umschließen Sie einen Signierer in HsmSignerProviderAdapter, wenn der Aufrufer über SignerProviderInterface arbeitet. Übergeben Sie die kanonische Provider-ID für die umschlossene Klasse — pkcs11-{module-id} oder openssl-cli —, damit Fähigkeitsprüfungen die korrekte Backend-Zulassungsmenge verwenden.

  • Verifizieren Sie vor dem Aktivieren der Post-Quantum-Vorschau die Mechanismus-Identifikatoren der Token-Firmware gegen die provisorischen Werte, die NextPDF registriert; eine Diskrepanz schlägt zur Signierzeit fehl. Aktivieren Sie die Vorschau nicht für produktive PAdES-Ausgabe.

  • getResolvedBackend() und getOpensslVersion() existieren zur Beweisaufzeichnung; persistieren Sie sie zusammen mit Signierbeweisen, wenn Ihr Compliance-Programm Reproduzierbarkeit erfordert.

Diese Seite dokumentiert ausschließlich extern beobachtbares Verhalten und die unterstützte öffentliche API-Oberfläche. Interne Namespace-Pfade, Hilfsklassen, Mechanismus-Tabellen, Runbook-Dateinamen und Ticket-Präfixe liegen außerhalb des Geltungsbereichs.