Ga naar inhoud
getnextpdf.com

Enterprise editie

HSM-ondertekening — Diepe referentie

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.

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.

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.

SymboolParametersStandaardgedragRetourneertGooit of faalt metOpmerkingen
Pkcs11Signer::__construct()string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = nullOpent de leveranciersbibliotheek, logt in op het slot en laadt het certificaat en de sleutelalgoritme-metadata van het tokenHsmOperationException wanneer ext-pkcs11 ontbreekt of tokentoegang faaltEé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-Valuestring ruwe handtekeningbytesHsmOperationException (sleutel niet gevonden, tokenfout); InvalidArgumentException (niet-gemapt algoritme); FIPS-gate-excepties vóór ondertekening wanneer een enforcer is bedraadGesloten algoritmeset; zie Gedragscontract
Pkcs11Signer::signPqs()string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = trueGeweigerd tenzij $enablePostQuantum was ingesteld; dispatcht het provisionele PKCS#11 PQ-mechanismestring ruwe handtekeningbytesHsmOperationException (uitgeschakeld, tokenfout, mismatch handtekeninglengte); InvalidArgumentException (context langer dan 255 bytes)Preview; geen conformiteitsclaim; mechanisme-identifiers zijn provisioneel
Pkcs11Signer::isPostQuantumEnabled()GeenRapporteert de opt-in-vlag van de constructorboolGeen
Pkcs11Signer::getCertificateDer()GeenRetourneert het ondertekenaarscertificaat dat van het token is gelezenstring (DER)GeenEenmalig geladen bij constructie
Pkcs11Signer::getCertificateChainDer()GeenRetourneert de door de constructor aangeleverde intermediairenarray<string> (DER)GeenExclusief 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 = nullVerifieert proc_open, sondeert de binary en versie, resolvet de backend en laadt de certificatenHsmOperationException (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-bestandstring ruwe handtekeningbytesHsmOperationException (time-out, PIN geweigerd, sleutel niet gevonden, module-laadfout, lege uitvoer, pin-bestandsfout); InvalidArgumentException (niet-gemapt algoritme); FIPS-gate-excepties vóór ondertekeningHet subproces wordt gedood na $timeoutSeconds; stderr wordt geredigeerd voordat het de berichten bereikt
OpenSslCliSigner accessor-oppervlakGeenAlleen-lezen constructieresultatenstring / array<string> / OpenSslCliBackendGeengetCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion
HsmSignerProviderAdapter::__construct()HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15Verpakt een HSM-concreet type als een SignerProviderInterfaceGeenConventies voor provider-id: pkcs11-{module-id}, openssl-cli
HsmSignerProviderAdapter::providerId()GeenRetourneert de door de constructor aangeleverde idnon-empty-stringGeen
HsmSignerProviderAdapter::supportsAlgorithm()SignatureAlgorithm $algoMapt de enum naar een OpenSSL-achtige naam en snijdt dan met de toegestane backendsetboolGeenWijst digest-only-algoritmen af; openssl-engine-id’s adverteren niets
HsmSignerProviderAdapter::sign()string $data, ?string $keyVersion = nullDispatcht via de verpakte ondertekenaar met het geconfigureerde algoritmenon-empty-stringKeyManagementException (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'): 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
  • Sleutelcustody. De privésleutel verlaat nooit de tokengrens. Pkcs11Signer delegeert de operatie aan het token; OpenSslCliSigner geeft een sleutelreferentie — een PKCS#11-URI — door aan het openssl-subproces. Geen van beide ondertekenaars kan de sleutel exporteren.
  • Sessie en login. Pkcs11Signer cachet éé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. Pkcs11Signer accepteert daarnaast ecdsa-raw. Elke andere identifier gooit InvalidArgumentException — 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-gecodeerde ECDSA-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 = true wordt de PIN als pin-value in de URI ingebed, wat observeerbaar is in de proces-commandoregel; deze modus is uitsluitend opt-in.
  • Subprocesdiscipline. OpenSslCliSigner spawnt 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 $keyVersion met KeyManagementException in 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 gooit SignatureFailedException.
  • 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 geselecteerde Pkcs11PqsAlgorithm-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.
  • Het construeren van Pkcs11Signer zonder ext-pkcs11 gooit onmiddellijk HsmOperationException; de extensie wordt niet meegeleverd met standaard PHP-distributies.
  • Een certificaat- of privésleutellabel dat met geen enkel object op het token overeenkomt gooit HsmOperationException met 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).
  • OpenSslCliSigner weigert bij constructie een $keyUri die al pin-value bevat, 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 HsmOperationException in plaats van de fout uit te stellen tot het ondertekenen.
  • Een subproces dat $timeoutSeconds overschrijdt 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.
  • HsmSignerProviderAdapter met de uitgefaseerde openssl-engine-provider-id adverteert geen algoritmen, zodat een verouderde configuratie faalt bij de providerselectie in plaats van bij het ondertekenen.

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.

ClaimStandaardClausule
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.1CKA_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 204HashML-DSA context handling
FIPS 140-3-validatie hecht zich aan cryptografische modules via de CMVP.FIPS 140-3CMVP 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.

  • 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-pkcs11 laadt voordat je Pkcs11Signer construeert; de constructie faalt snel wanneer de extensie ontbreekt. De CLI-ondertekenaar vereist dat proc_open is ingeschakeld en een openssl-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 HsmSignerProviderAdapter wanneer de aanroeper via SignerProviderInterface werkt. Geef de canonieke provider-id voor de verpakte klasse door — pkcs11-{module-id} of openssl-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() en getOpensslVersion() bestaan voor bewijsregistratie; persisteer ze samen met het ondertekeningsbewijs wanneer je compliance-programma reproduceerbaarheid vereist.

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.