Salta ai contenuti
getnextpdf.com

Enterprise edizione

Firma HSM — Riferimento approfondito

Questa pagina è il riferimento approfondito della superficie di firma HSM di NextPDF Enterprise. Copre tre tipi pubblici. NextPDF\Enterprise\Security\Signature\Hsm\Pkcs11Signer firma tramite un token PKCS#11 attraverso l’estensione ext-pkcs11. NextPDF\Enterprise\Security\Signature\Hsm\OpenSslCliSigner firma tramite il binario openssl in un sottoprocesso, per chiavi supportate da provider o engine che PHP ext-openssl non è in grado di caricare. NextPDF\Enterprise\Security\Signature\Hsm\Provider\HsmSignerProviderAdapter espone entrambe le concretizzazioni come una SignerProviderInterface unificata. In ogni percorso la chiave privata resta all’interno del confine del token; NextPDF trasmette i byte da firmare e riceve la firma. Il percorso post-quantum (signPqs) è una anteprima: è disabilitato per impostazione predefinita, non porta con sé alcuna dichiarazione di conformità e non ha un percorso di verifica supportato negli attuali validatori PDF. NextPDF non detiene alcuna certificazione e non ne concede alcuna; il supporto non equivale alla conformità e la conformità non equivale alla certificazione.

Questa capacità è distribuita in NextPDF Enterprise (nextpdf/enterprise) e si attiva con un envelope di licenza di tier Enterprise. Un deployment privo di tale abilitazione non carica le classi della capacità. Confronta le edizioni e ottieni una licenza.

Tutti e tre i tipi risiedono in NextPDF\Enterprise\Security\Signature\Hsm; l’adattatore si trova nel suo sotto-namespace Provider. Entrambi i signer implementano il contratto Core NextPDF\Contracts\HsmSignerInterface.

SimboloParametriComportamento predefinitoRestituisceSolleva o fallisce conNote
Pkcs11Signer::__construct()string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = nullApre la libreria del fornitore, effettua il login nello slot e carica il certificato e i metadati dell’algoritmo della chiave dal tokenHsmOperationException quando ext-pkcs11 è assente o l’accesso al token fallisceUn handle di modulo viene messo in cache per ogni percorso di libreria per processo; PIN ed etichette sono #[SensitiveParameter]
Pkcs11Signer::sign()string $data, string $algorithm = 'sha256WithRSAEncryption'Firma sul token; l’output ECDSA grezzo viene convertito in DER ECDSA-Sig-Valuestring byte grezzi della firmaHsmOperationException (chiave non trovata, errore del token); InvalidArgumentException (algoritmo non mappato); eccezioni del gate FIPS prima della firma quando è collegato un enforcerInsieme chiuso di algoritmi; vedi Contratto di comportamento
Pkcs11Signer::signPqs()string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = trueRifiutata a meno che $enablePostQuantum non sia stato impostato; invoca il meccanismo PQ PKCS#11 provvisoriostring byte grezzi della firmaHsmOperationException (disabilitata, errore del token, lunghezza della firma non corrispondente); InvalidArgumentException (contesto oltre 255 byte)Anteprima; nessuna dichiarazione di conformità; gli identificatori dei meccanismi sono provvisori
Pkcs11Signer::isPostQuantumEnabled()NessunoRiporta il flag di opt-in del costruttoreboolNessuno
Pkcs11Signer::getCertificateDer()NessunoRestituisce il certificato del firmatario letto dal tokenstring (DER)NessunoCaricato una sola volta alla costruzione
Pkcs11Signer::getCertificateChainDer()NessunoRestituisce gli intermedi forniti dal costruttorearray<string> (DER)NessunoEsclude il certificato del firmatario
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 = nullVerifica proc_open, sonda il binario e la versione, risolve il backend e carica i certificatiHsmOperationException (proc_open disabilitato, file di modulo/config/certificato mancante, errore del binario, nessun backend); InvalidArgumentException (pin-value all’interno di $keyUri)OpenSslCliBackend::Auto preferisce il provider OpenSSL 3.x, poi l’engine
OpenSslCliSigner::sign()string $data, string $algorithm = 'sha256WithRSAEncryption'Esegue openssl dgst in un sottoprocesso; per impostazione predefinita il PIN transita attraverso un file pin-source effimero 0600string byte grezzi della firmaHsmOperationException (timeout, PIN rifiutato, chiave non trovata, errore di caricamento del modulo, output vuoto, errore del file PIN); InvalidArgumentException (algoritmo non mappato); eccezioni del gate FIPS prima della firmaIl sottoprocesso viene terminato dopo $timeoutSeconds; lo stderr viene redatto prima di raggiungere i messaggi
Superficie di accesso OpenSslCliSignerNessunoRisultati di costruzione in sola letturastring / array<string> / OpenSslCliBackendNessunogetCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion
HsmSignerProviderAdapter::__construct()HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15Incapsula una concretizzazione HSM come SignerProviderInterfaceNessunoConvenzioni per l’id del provider: pkcs11-{module-id}, openssl-cli
HsmSignerProviderAdapter::providerId()NessunoRestituisce l’id fornito dal costruttorenon-empty-stringNessuno
HsmSignerProviderAdapter::supportsAlgorithm()SignatureAlgorithm $algoMappa l’enum su un nome in stile OpenSSL, poi interseca con l’insieme consentito del backendboolNessunoRifiuta gli algoritmi solo-digest; gli id openssl-engine non annunciano nulla
HsmSignerProviderAdapter::sign()string $data, ?string $keyVersion = nullInvoca il signer incapsulato con l’algoritmo configuratonon-empty-stringKeyManagementException ($keyVersion non nullo); SignatureFailedException (algoritmo non mappabile, errore del driver, firma vuota)Contratto SPI fail-closed; ogni errore del driver emerge tipizzato
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
  • Custodia delle chiavi. La chiave privata non lascia mai il confine del token. Pkcs11Signer delega l’operazione al token; OpenSslCliSigner passa un riferimento alla chiave — un URI PKCS#11 — al sottoprocesso openssl. Nessuno dei due signer può esportare la chiave.
  • Sessione e login. Pkcs11Signer mette in cache un solo handle di modulo PKCS#11 per percorso di libreria per processo, perché l’interfaccia del token deve essere inizializzata esattamente una volta per processo. Ogni operazione apre una sessione ed effettua il login con il PIN; il login autentica l’utente prima di qualsiasi uso della chiave privata (PKCS#11 v3.1 §5.6.8). Quando lo slot segnala un login esistente, il signer effettua il logout e il login di nuovo, così i token che richiedono un PIN fresco per ogni operazione ne ricevono uno.
  • Insieme di algoritmi (chiuso). Entrambi i signer accettano esattamente: sha256WithRSAEncryption, sha384WithRSAEncryption, sha512WithRSAEncryption; RSASSA-PSS, RSASSA-PSS-SHA256, RSASSA-PSS-SHA384, RSASSA-PSS-SHA512; ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512. Pkcs11Signer accetta inoltre ecdsa-raw. Qualsiasi altro identificatore solleva InvalidArgumentException — non viene mai firmato alcun algoritmo sostitutivo.
  • Vincolo del salt PSS. Per ogni variante PSS la lunghezza del salt è uguale alla lunghezza del digest — 32, 48 o 64 byte — e i parametri hash e MGF corrispondono al digest scelto. Ciò segue la struttura dei parametri del meccanismo PSS, dove la lunghezza del salt è tipicamente la lunghezza dell’hash del messaggio (PKCS#11 v3.1 §6.1.9). Entrambi i signer applicano lo stesso abbinamento, così una configurazione valida su un backend è valida sull’altro.
  • Conversione ECDSA. Un token restituisce una firma ECDSA come concatenazione grezza e riempita con zeri di r e s (PKCS#11 v3.1 §6.3.1). Pkcs11Signer::sign() converte quell’output nella forma DER-encoded ECDSA-Sig-Value che i validatori PDF e OpenSSL si aspettano. Il chiamante non gestisce mai la forma grezza.
  • Consegna del PIN (percorso CLI). Nella modalità predefinita sicura, il PIN viene scritto in un file effimero creato esclusivamente con permessi riservati al solo proprietario, referenziato tramite l’attributo pin-source dell’URI PKCS#11 e rimosso dopo l’uscita del sottoprocesso. In questa modalità il PIN non viene collocato nella riga di comando e non viene esportato nell’ambiente del sottoprocesso. Con $legacyPinDelivery = true, il PIN viene incorporato come pin-value nell’URI, il che è osservabile nella riga di comando del processo; questa modalità è solo su opt-in.
  • Disciplina del sottoprocesso. OpenSslCliSigner avvia il binario con un array di argomenti — nessuna interpolazione di shell — impone $timeoutSeconds, termina il sottoprocesso alla scadenza e classifica lo stderr in errori tipizzati. I segreti vengono redatti dallo stderr prima che sia citato in un messaggio di eccezione.
  • Semantica dell’adattatore. Un token HSM non ha un concetto gestito di versione della chiave; la chiave sul token è la versione. HsmSignerProviderAdapter::sign() rifiuta pertanto qualsiasi $keyVersion non nullo con KeyManagementException invece di ignorarlo. supportsAlgorithm() interseca la mappatura dell’enum con l’insieme accettato dal backend incapsulato, così l’adattatore non annuncia mai un meccanismo che il backend rifiuterebbe al momento della firma. Una firma vuota dal driver solleva SignatureFailedException.
  • Anteprima post-quantum. signPqs() è protetta dal flag del costruttore $enablePostQuantum e rifiuta di essere eseguita altrimenti. La stringa di contesto è limitata a 255 byte, in linea con il limite del contesto ML-DSA (FIPS 204). La firma restituita deve corrispondere all’esatta lunghezza in byte del set di parametri Pkcs11PqsAlgorithm selezionato, altrimenti la chiamata fallisce. Gli identificatori dei meccanismi seguono un’estensione PQ PKCS#11 provvisoria e non sono definitivi. I profili PAdES non riconoscono le suite post-quantum, la maggior parte dei validatori PDF rifiuta tali firme e NextPDF non fornisce alcun percorso di verifica per esse. Non viene dichiarata alcuna conformità.
  • Costruire Pkcs11Signer senza ext-pkcs11 solleva immediatamente HsmOperationException; l’estensione non è inclusa nelle distribuzioni PHP standard.
  • Un’etichetta di certificato o di chiave privata che non corrisponde ad alcun oggetto sul token solleva HsmOperationException indicando la classe di oggetto mancante. L’etichetta della chiave può legittimamente differire dall’etichetta del certificato su alcuni token.
  • Login falliti ripetuti possono bloccare il PIN sul token; è il token a imporre tale politica, non NextPDF. I token le cui chiavi richiedono l’autenticazione a ogni uso ricevono un login fresco tramite il percorso logout-e-riprova (PKCS#11 v3.1, semantica always-authenticate).
  • OpenSslCliSigner rifiuta alla costruzione un $keyUri che contiene già pin-value, in modalità fail-closed, perché quella consegna aggirerebbe il percorso sicuro del PIN.
  • Su Windows, la modalità sicura con file PIN fallisce fail-closed con HsmOperationException: i bit di permesso dei file non possono limitare le concessioni di lettura ACL in quel contesto, quindi il signer rifiuta di lasciare un PIN in chiaro sull’ACL della directory temporanea. La consegna del PIN legacy è l’alternativa documentata su opt-in per host Windows fidati.
  • Il rilevamento automatico del backend richiede OpenSSL 3.x per il percorso provider; LibreSSL non si risolve mai sul provider. Quando né una sonda del provider né una dell’engine ha successo, la costruzione fallisce con HsmOperationException invece di rinviare l’errore al momento della firma.
  • Un sottoprocesso che supera $timeoutSeconds viene terminato e segnalato come timeout; un sottoprocesso che esce in modo pulito con output vuoto viene segnalato come errore di firma vuota. Nessuna delle due condizioni può produrre un documento parzialmente firmato.
  • Una firma post-quantum la cui lunghezza in byte non corrisponde al set di parametri selezionato viene rifiutata prima di poter raggiungere la codifica CMS.
  • HsmSignerProviderAdapter con l’id del provider ritirato openssl-engine non annuncia alcun algoritmo, quindi una configurazione obsoleta fallisce alla selezione del provider invece che al momento della firma.

Entrambi i signer accettano un FipsSignatureEnforcer opzionale. Quando ne è collegato uno, la modalità FIPS è attiva per quel signer: sign() rifiuta un algoritmo di firma non consentito o una chiave sotto-soglia prima che avvenga qualsiasi firma sul token o nel sottoprocesso. Le soglie seguono la tabella di generazione della firma — i moduli RSA sotto i 2048 bit e gli ordini ECDSA sotto i 224 bit non sono consentiti (NIST SP 800-131A Rev.2 §3 Table 2). Senza enforcer, il comportamento è invariato. Il gate copre solo il percorso classico sign(); signPqs() è governata dal proprio flag di anteprima. Queste sono dichiarazioni di capacità sul codice NextPDF: la validazione FIPS 140-3 si attribuisce a un modulo crittografico tramite il CMVP, che in questo deployment è l’HSM o il provider dell’operatore — NextPDF non è un modulo validato, non detiene alcuna certificazione e non ne concede alcuna.

DichiarazioneStandardClausola
Il login autentica l’utente sul token prima delle operazioni con chiave privata; un PIN errato nega l’accesso.PKCS#11 v3.1§5.6.8
Le chiavi always-authenticate necessitano di un login fresco a ogni uso; ri-autenticazioni fallite ripetute possono bloccare il PIN.PKCS#11 v3.1CKA_ALWAYS_AUTHENTICATE re-authentication
Una firma ECDSA del token è la concatenazione grezza r‖s; il signer la converte in DER per l’interoperabilità PDF.PKCS#11 v3.1§6.3.1
I parametri PSS vincolano hash, MGF e lunghezza del salt; i signer impostano il salt uguale alla lunghezza del digest.PKCS#11 v3.1§6.1.9
Il gate FIPS nega la generazione della firma con RSA sotto i 2048 bit o ordine ECDSA sotto i 224 bit.NIST SP 800-131A Rev.2§3 Table 2
La stringa di contesto post-quantum è limitata a 255 byte.FIPS 204HashML-DSA context handling
La validazione FIPS 140-3 si attribuisce ai moduli crittografici tramite il CMVP.FIPS 140-3CMVP program scope

Tutte le clausole sono parafrasate; nessun testo normativo è riprodotto. NextPDF non avanza alcuna dichiarazione di certificazione. I signer allineano il proprio comportamento alle clausole citate come capacità. Se una firma prodotta verifichi è decisione del verificatore rispetto ai propri trust anchor; la sicurezza della chiave dipende dal token, dall’HSM e dall’operatore — non da NextPDF da solo.

  • Il meccanismo di consegna del PIN segue la convenzione pin-source dell’URI PKCS#11 (RFC 7512); quella RFC è al di fuori del corpus citato, quindi il comportamento sopra descritto è fondato sul codice sorgente del prodotto, non su una citazione di specifica.

  • Conferma che il runtime carichi ext-pkcs11 prima di costruire Pkcs11Signer; la costruzione fallisce rapidamente quando l’estensione è assente. Il signer CLI necessita di proc_open abilitato e di un binario openssl con un provider o engine PKCS#11 installato.

  • Il PIN, l’etichetta del certificato e l’etichetta della chiave sono #[SensitiveParameter], quindi sono esclusi dagli stack trace. Fornisci il PIN da un secret manager; non scriverlo mai nel sorgente, nella configurazione committata nel controllo di versione o nei log.

  • La costruzione è il passo costoso su entrambi i signer: il percorso PKCS#11 effettua il login e legge il certificato, e il percorso CLI sonda il binario e il backend. Costruisci una volta e riutilizza l’istanza; la cache di modulo per libreria rende sicura la costruzione ripetuta contro la stessa libreria.

  • Incapsula un signer in HsmSignerProviderAdapter quando il chiamante lavora tramite SignerProviderInterface. Passa l’id canonico del provider per la classe incapsulata — pkcs11-{module-id} o openssl-cli — così i controlli di capacità usano l’insieme consentito del backend corretto.

  • Prima di abilitare l’anteprima post-quantum, verifica gli identificatori dei meccanismi del firmware del token rispetto ai valori provvisori che NextPDF registra; una discordanza fallisce al momento della firma. Non abilitare l’anteprima per output PAdES di produzione.

  • getResolvedBackend() e getOpensslVersion() esistono per la registrazione delle prove; conservali con le prove di firma quando il tuo programma di conformità richiede la riproducibilità.

Questa pagina documenta solo il comportamento osservabile esternamente e la superficie API pubblica supportata. I percorsi di namespace interni, le classi helper, le tabelle dei meccanismi, i nomi di file dei runbook e i prefissi dei ticket sono fuori ambito.