Enterprise editie
HSM-ondertekening — Diepe referentie
In één oogopslag
Sectie met titel “In één oogopslag”Deze pagina is de diepgaande referentie voor het NextPDF Enterprise HSM-ondertekeningsoppervlak. Ze behandelt drie publieke typen. NextPDF\Enterprise\Security\Signature\Hsm\Pkcs11Signer ondertekent via een PKCS#11-token met de ext-pkcs11-extensie. NextPDF\Enterprise\Security\Signature\Hsm\OpenSslCliSigner ondertekent via de openssl-binary in een subproces, voor provider- of engine-gedekte sleutels die PHP ext-openssl niet kan laden. NextPDF\Enterprise\Security\Signature\Hsm\Provider\HsmSignerProviderAdapter stelt elk concreet type beschikbaar als een uniforme SignerProviderInterface. In elk pad blijft de privésleutel binnen de tokengrens; NextPDF geeft de te ondertekenen bytes door en ontvangt de handtekening. Het post-quantumpad (signPqs) is een preview: het is standaard uitgeschakeld, draagt geen conformiteitsclaim en heeft geen ondersteund verificatiepad in de huidige PDF-validators. NextPDF houdt geen certificering aan en verleent er geen; ondersteuning staat niet gelijk aan conformiteit, en conformiteit staat niet gelijk aan certificering.
Beschikbaarheid & licentiëring
Sectie met titel “Beschikbaarheid & licentiëring”Deze mogelijkheid wordt geleverd in NextPDF Enterprise (nextpdf/enterprise) en wordt geactiveerd met een licentie-envelop op Enterprise-niveau. Een deployment zonder die aanspraak laadt de klassen van de mogelijkheid niet. Vergelijk edities en verkrijg een licentie.
Publiek API-oppervlak
Sectie met titel “Publiek API-oppervlak”Alle drie de typen bevinden zich in NextPDF\Enterprise\Security\Signature\Hsm; de adapter zit in de Provider-subnaamruimte. Beide ondertekenaars implementeren het Core-contract NextPDF\Contracts\HsmSignerInterface.
| Symbool | Parameters | Standaardgedrag | Retourneert | Gooit of faalt met | Opmerkingen |
|---|---|---|---|---|---|
Pkcs11Signer::__construct() | string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = null | Opent de leveranciersbibliotheek, logt in op het slot en laadt het certificaat en de sleutelalgoritme-metadata van het token | — | HsmOperationException wanneer ext-pkcs11 ontbreekt of tokentoegang faalt | Eén modulehandle wordt per bibliotheekpad per proces gecachet; PIN en labels zijn #[SensitiveParameter] |
Pkcs11Signer::sign() | string $data, string $algorithm = 'sha256WithRSAEncryption' | Ondertekent op het token; ruwe ECDSA-uitvoer wordt omgezet naar DER ECDSA-Sig-Value | string ruwe handtekeningbytes | HsmOperationException (sleutel niet gevonden, tokenfout); InvalidArgumentException (niet-gemapt algoritme); FIPS-gate-excepties vóór ondertekening wanneer een enforcer is bedraad | Gesloten algoritmeset; zie Gedragscontract |
Pkcs11Signer::signPqs() | string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true | Geweigerd tenzij $enablePostQuantum was ingesteld; dispatcht het provisionele PKCS#11 PQ-mechanisme | string ruwe handtekeningbytes | HsmOperationException (uitgeschakeld, tokenfout, mismatch handtekeninglengte); InvalidArgumentException (context langer dan 255 bytes) | Preview; geen conformiteitsclaim; mechanisme-identifiers zijn provisioneel |
Pkcs11Signer::isPostQuantumEnabled() | Geen | Rapporteert de opt-in-vlag van de constructor | bool | Geen | — |
Pkcs11Signer::getCertificateDer() | Geen | Retourneert het ondertekenaarscertificaat dat van het token is gelezen | string (DER) | Geen | Eenmalig geladen bij constructie |
Pkcs11Signer::getCertificateChainDer() | Geen | Retourneert de door de constructor aangeleverde intermediairen | array<string> (DER) | Geen | Exclusief het ondertekenaarscertificaat |
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 = null | Verifieert proc_open, sondeert de binary en versie, resolvet de backend en laadt de certificaten | — | HsmOperationException (proc_open uitgeschakeld, ontbrekend module-/config-/certificaatbestand, binaryfout, geen backend); InvalidArgumentException (pin-value binnen $keyUri) | OpenSslCliBackend::Auto verkiest de OpenSSL 3.x-provider, dan de engine |
OpenSslCliSigner::sign() | string $data, string $algorithm = 'sha256WithRSAEncryption' | Voert openssl dgst uit in een subproces; de PIN reist standaard via een kortstondig 0600 pin-source-bestand | string ruwe handtekeningbytes | HsmOperationException (time-out, PIN geweigerd, sleutel niet gevonden, module-laadfout, lege uitvoer, pin-bestandsfout); InvalidArgumentException (niet-gemapt algoritme); FIPS-gate-excepties vóór ondertekening | Het subproces wordt gedood na $timeoutSeconds; stderr wordt geredigeerd voordat het de berichten bereikt |
OpenSslCliSigner accessor-oppervlak | Geen | Alleen-lezen constructieresultaten | string / array<string> / OpenSslCliBackend | Geen | getCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion |
HsmSignerProviderAdapter::__construct() | HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15 | Verpakt een HSM-concreet type als een SignerProviderInterface | — | Geen | Conventies voor provider-id: pkcs11-{module-id}, openssl-cli |
HsmSignerProviderAdapter::providerId() | Geen | Retourneert de door de constructor aangeleverde id | non-empty-string | Geen | — |
HsmSignerProviderAdapter::supportsAlgorithm() | SignatureAlgorithm $algo | Mapt de enum naar een OpenSSL-achtige naam en snijdt dan met de toegestane backendset | bool | Geen | Wijst digest-only-algoritmen af; openssl-engine-id’s adverteren niets |
HsmSignerProviderAdapter::sign() | string $data, ?string $keyVersion = null | Dispatcht via de verpakte ondertekenaar met het geconfigureerde algoritme | non-empty-string | KeyManagementException (niet-null $keyVersion); SignatureFailedException (niet-mapbaar algoritme, driverfout, lege handtekening) | Fail-closed SPI-contract; elke driverfout komt getypeerd naar boven |
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'): stringpublic function signPqs(string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true): stringpublic function isPostQuantumEnabled(): boolpublic function getCertificateDer(): stringpublic function getCertificateChainDer(): arraypublic 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'): stringpublic function getCertificateDer(): stringpublic function getCertificateChainDer(): arraypublic function getPublicKeyAlgorithm(): stringpublic function getCertificatePem(): stringpublic function getResolvedBackend(): OpenSslCliBackendpublic function getOpensslVersion(): stringpublic function __construct(private HsmSignerInterface $hsm, private string $providerId, private SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15)public function providerId(): stringpublic function supportsAlgorithm(SignatureAlgorithm $algo): boolpublic function sign(string $data, ?string $keyVersion = null): stringGedragscontract
Sectie met titel “Gedragscontract”- Sleutelcustody. De privésleutel verlaat nooit de tokengrens.
Pkcs11Signerdelegeert de operatie aan het token;OpenSslCliSignergeeft een sleutelreferentie — een PKCS#11-URI — door aan hetopenssl-subproces. Geen van beide ondertekenaars kan de sleutel exporteren. - Sessie en login.
Pkcs11Signercachet één PKCS#11-modulehandle per bibliotheekpad per proces, omdat de tokeninterface precies één keer per proces geïnitialiseerd moet worden. Elke operatie opent een sessie en logt in met de PIN; de login authenticeert de gebruiker vóór elk privésleutelgebruik (PKCS#11 v3.1 §5.6.8). Wanneer het slot een bestaande login rapporteert, logt de ondertekenaar uit en weer in, zodat tokens die per operatie een verse PIN eisen er een ontvangen. - Algoritmeset (gesloten). Beide ondertekenaars accepteren precies:
sha256WithRSAEncryption,sha384WithRSAEncryption,sha512WithRSAEncryption;RSASSA-PSS,RSASSA-PSS-SHA256,RSASSA-PSS-SHA384,RSASSA-PSS-SHA512;ecdsa-with-SHA256,ecdsa-with-SHA384,ecdsa-with-SHA512.Pkcs11Signeraccepteert daarnaastecdsa-raw. Elke andere identifier gooitInvalidArgumentException— er wordt nooit een vervangend algoritme ondertekend. - PSS-salt-binding. Voor elke PSS-variant is de saltlengte gelijk aan de digestlengte — 32, 48 of 64 bytes — en de hash- en MGF-parameters komen overeen met de gekozen digest. Dit volgt de PSS-mechanisme-parameterstructuur, waarin de saltlengte doorgaans de lengte van de boodschap-hash is (PKCS#11 v3.1 §6.1.9). Beide ondertekenaars passen dezelfde koppeling toe, dus een configuratie die geldig is op de ene backend is geldig op de andere.
- ECDSA-conversie. Een token retourneert een ECDSA-handtekening als de ruwe, met nullen gevulde concatenatie van r en s (PKCS#11 v3.1 §6.3.1).
Pkcs11Signer::sign()zet die uitvoer om naar de DER-gecodeerdeECDSA-Sig-Value-vorm die PDF-validators en OpenSSL verwachten. De aanroeper verwerkt de ruwe vorm nooit. - PIN-levering (CLI-pad). In de veilige standaard wordt de PIN geschreven naar een kortstondig bestand dat exclusief met alleen-eigenaar-rechten wordt aangemaakt, gerefereerd via het
pin-source-attribuut van de PKCS#11-URI, en na afsluiting van het subproces ontkoppeld. De PIN wordt in deze modus niet in de commandoregel geplaatst en niet naar de subprocesomgeving geëxporteerd. Met$legacyPinDelivery = truewordt de PIN alspin-valuein de URI ingebed, wat observeerbaar is in de proces-commandoregel; deze modus is uitsluitend opt-in. - Subprocesdiscipline.
OpenSslCliSignerspawnt de binary met een argumentarray — geen shell-interpolatie — handhaaft$timeoutSeconds, doodt het subproces bij verloop, en classificeert stderr in getypeerde fouten. Geheimen worden geredigeerd uit stderr voordat het in een exceptiebericht wordt geciteerd. - Adaptersemantiek. Een HSM-token heeft geen beheerd sleutelversie-concept; de sleutel op het token is de versie.
HsmSignerProviderAdapter::sign()weigert daarom elke niet-null$keyVersionmetKeyManagementExceptionin plaats van hem te negeren.supportsAlgorithm()snijdt de enum-mapping met de geaccepteerde set van de verpakte backend, zodat de adapter nooit een mechanisme adverteert dat de backend bij het ondertekenen zou weigeren. Een lege handtekening van de driver gooitSignatureFailedException. - Post-quantum-preview.
signPqs()zit achter de$enablePostQuantum-constructorvlag en weigert anders uit te voeren. De contextstring is beperkt tot 255 bytes, overeenkomstig de ML-DSA-contextgrens (FIPS 204). De geretourneerde handtekening moet exact overeenkomen met de bytelengte van de geselecteerdePkcs11PqsAlgorithm-parameterset, anders faalt de aanroep. De mechanisme-identifiers volgen een provisionele PKCS#11 PQ-extensie en zijn niet definitief. PAdES-profielen herkennen geen post-quantumsuites, de meeste PDF-validators wijzen zulke handtekeningen af, en NextPDF biedt er geen verificatiepad voor. Er wordt geen conformiteit geclaimd.
Randgevallen & faalmodi
Sectie met titel “Randgevallen & faalmodi”- Het construeren van
Pkcs11Signerzonderext-pkcs11gooit onmiddellijkHsmOperationException; de extensie wordt niet meegeleverd met standaard PHP-distributies. - Een certificaat- of privésleutellabel dat met geen enkel object op het token overeenkomt gooit
HsmOperationExceptionmet vermelding van de ontbrekende objectklasse. Het sleutellabel mag op sommige tokens legitiem verschillen van het certificaatlabel. - Herhaalde mislukte logins kunnen de PIN aan het token vergrendelen; het token handhaaft dat beleid, niet NextPDF. Tokens waarvan de sleutels bij elk gebruik authenticatie vereisen ontvangen een verse login via het uitloggen-en-opnieuw-proberen-pad (PKCS#11 v3.1, always-authenticate-semantiek).
OpenSslCliSignerweigert bij constructie een$keyUridie alpin-valuebevat, fail-closed, omdat die levering het veilige PIN-pad zou omzeilen.- Op Windows faalt de veilige pin-bestandsmodus fail-closed met
HsmOperationException: bestandsrechtenbits kunnen daar ACL-leesverleningen niet beperken, dus de ondertekenaar weigert een cleartext-PIN achter te laten in de ACL van de temp-directory. Legacy PIN-levering is het gedocumenteerde, opt-in-alternatief voor vertrouwde Windows-hosts. - Backend-autodetectie vereist OpenSSL 3.x voor het providerpad; LibreSSL resolvet nooit naar de provider. Wanneer noch een provider- noch een engine-sondering slaagt, faalt de constructie met
HsmOperationExceptionin plaats van de fout uit te stellen tot het ondertekenen. - Een subproces dat
$timeoutSecondsoverschrijdt wordt beëindigd en gerapporteerd als een time-out; een subproces dat schoon afsluit met lege uitvoer wordt gerapporteerd als een lege-handtekening-fout. Geen van beide condities kan een gedeeltelijk ondertekend document opleveren. - Een post-quantum-handtekening waarvan de bytelengte niet overeenkomt met de geselecteerde parameterset wordt afgewezen voordat ze de CMS-codering kan bereiken.
HsmSignerProviderAdaptermet de uitgefaseerdeopenssl-engine-provider-id adverteert geen algoritmen, zodat een verouderde configuratie faalt bij de providerselectie in plaats van bij het ondertekenen.
FIPS-modusgedrag
Sectie met titel “FIPS-modusgedrag”Beide ondertekenaars accepteren een optionele FipsSignatureEnforcer. Wanneer er een bedraad is, is de FIPS-modus actief voor die ondertekenaar: sign() wijst een niet-toegestaan handtekeningalgoritme of een sub-floor-sleutel af voordat enige token- of subprocesondertekening plaatsvindt. De ondergrenzen volgen de tabel voor handtekeninggeneratie — RSA-moduli onder 2048 bits en ECDSA-orden onder 224 bits zijn niet toegestaan (NIST SP 800-131A Rev.2 §3 Table 2). Zonder enforcer blijft het gedrag ongewijzigd. De gate dekt alleen het klassieke sign()-pad; signPqs() wordt beheerst door zijn eigen preview-vlag. Dit zijn capaciteitsclaims over NextPDF-code: FIPS 140-3-validatie hecht zich aan een cryptografische module via de CMVP, wat in deze deployment de HSM of provider van de operator is — NextPDF is geen gevalideerde module, houdt geen certificering aan en verleent er geen.
Conformiteit
Sectie met titel “Conformiteit”| Claim | Standaard | Clausule |
|---|---|---|
| Login authenticeert de gebruiker aan het token vóór privésleuteloperaties; een verkeerde PIN weigert toegang. | PKCS#11 v3.1 | §5.6.8 |
| Always-authenticate-sleutels hebben per gebruik een verse login nodig; herhaalde mislukte herauthenticatie kan de PIN vergrendelen. | PKCS#11 v3.1 | CKA_ALWAYS_AUTHENTICATE re-authentication |
| Een token-ECDSA-handtekening is de ruwe r‖s-concatenatie; de ondertekenaar zet die om naar DER voor PDF-interoperabiliteit. | PKCS#11 v3.1 | §6.3.1 |
| PSS-parameters binden hash, MGF en saltlengte; de ondertekenaars zetten de salt gelijk aan de digestlengte. | PKCS#11 v3.1 | §6.1.9 |
| De FIPS-gate weigert handtekeninggeneratie met RSA onder 2048 bits of ECDSA-orde onder 224 bits. | NIST SP 800-131A Rev.2 | §3 Table 2 |
| De post-quantum-contextstring is beperkt tot 255 bytes. | FIPS 204 | HashML-DSA context handling |
| FIPS 140-3-validatie hecht zich aan cryptografische modules via de CMVP. | FIPS 140-3 | CMVP program scope |
Alle clausules zijn geparafraseerd; er wordt geen normatieve tekst gereproduceerd. NextPDF doet geen certificeringsclaim. De ondertekenaars stemmen hun gedrag af op de geciteerde clausules als een capaciteit. Of een geproduceerde handtekening verifieert is de beslissing van de verifieerder tegen zijn trust anchors; sleutelbeveiliging hangt af van het token, de HSM en de operator — niet van NextPDF alleen.
Ontwikkelnotities
Sectie met titel “Ontwikkelnotities”-
Het PIN-leveringsmechanisme volgt de
pin-source-conventie van de PKCS#11-URI (RFC 7512); die RFC valt buiten het geciteerde corpus, dus het bovenstaande gedrag is gegrond op de productbroncode, niet op een spec-citatie. -
Bevestig dat de runtime
ext-pkcs11laadt voordat jePkcs11Signerconstrueert; de constructie faalt snel wanneer de extensie ontbreekt. De CLI-ondertekenaar vereist datproc_openis ingeschakeld en eenopenssl-binary met een PKCS#11-provider of -engine geïnstalleerd. -
De PIN, het certificaatlabel en het sleutellabel zijn
#[SensitiveParameter], dus ze worden uitgesloten van stack traces. Lever de PIN aan vanuit een secret manager; schrijf hem nooit naar broncode, naar in versiebeheer vastgelegde configuratie, of naar logs. -
Constructie is de dure stap op beide ondertekenaars: het PKCS#11-pad logt in en leest het certificaat, en het CLI-pad sondeert de binary en backend. Construeer eenmaal en hergebruik de instantie; de per-bibliotheek-modulecache maakt herhaalde constructie tegen dezelfde bibliotheek veilig.
-
Verpak een ondertekenaar in
HsmSignerProviderAdapterwanneer de aanroeper viaSignerProviderInterfacewerkt. Geef de canonieke provider-id voor de verpakte klasse door —pkcs11-{module-id}ofopenssl-cli— zodat capaciteitscontroles de juiste toegestane backendset gebruiken. -
Verifieer vóór het inschakelen van de post-quantum-preview de mechanisme-identifiers van de tokenfirmware tegen de provisionele waarden die NextPDF registreert; een mismatch faalt bij het ondertekenen. Schakel de preview niet in voor productie-PAdES-uitvoer.
-
getResolvedBackend()engetOpensslVersion()bestaan voor bewijsregistratie; persisteer ze samen met het ondertekeningsbewijs wanneer je compliance-programma reproduceerbaarheid vereist.
Zie ook
Sectie met titel “Zie ook”- Hardware security module-ondertekening (PKCS#11) — de capaciteitspagina met setup, configuratie en verificatiestappen.
- Security — Diepgaande referentie — het gecombineerde Enterprise-beveiligingsoppervlak.
- Signature — Diepgaande referentie — de PAdES B-LT / B-LTA langetermijnproducent.
- FIPS 140 — Diepgaande referentie — het cryptobeleid, de zelftest-batterij en de
FipsSignatureEnforcer-gate. - PQC-preview — Diepgaande referentie — het post-quantum-preview-oppervlak en zijn grenzen.
- Security / Signing (Core) — de Core CMS-ondertekenaar en de ondertekeningscontracten.
Publicatiegrens
Sectie met titel “Publicatiegrens”Deze pagina documenteert uitsluitend extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne naamruimtepaden, helperklassen, mechanismetabellen, runbook-bestandsnamen en ticketprefixen vallen buiten de scope.