Enterprise edizione
Firma HSM — Riferimento approfondito
In sintesi
Sezione intitolata “In sintesi”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.
Disponibilità e licenze
Sezione intitolata “Disponibilità e licenze”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.
Superficie API pubblica
Sezione intitolata “Superficie API pubblica”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.
| Simbolo | Parametri | Comportamento predefinito | Restituisce | Solleva o fallisce con | Note |
|---|---|---|---|---|---|
Pkcs11Signer::__construct() | string $libraryPath, int $slotId, string $pin, string $certLabel, ?string $keyLabel = null, array $chainDer = [], bool $enablePostQuantum = false, ?FipsSignatureEnforcer $fipsEnforcer = null | Apre la libreria del fornitore, effettua il login nello slot e carica il certificato e i metadati dell’algoritmo della chiave dal token | — | HsmOperationException quando ext-pkcs11 è assente o l’accesso al token fallisce | Un 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-Value | string byte grezzi della firma | HsmOperationException (chiave non trovata, errore del token); InvalidArgumentException (algoritmo non mappato); eccezioni del gate FIPS prima della firma quando è collegato un enforcer | Insieme chiuso di algoritmi; vedi Contratto di comportamento |
Pkcs11Signer::signPqs() | string $data, Pkcs11PqsAlgorithm $algorithm, string $context = '', bool $randomized = true | Rifiutata a meno che $enablePostQuantum non sia stato impostato; invoca il meccanismo PQ PKCS#11 provvisorio | string byte grezzi della firma | HsmOperationException (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() | Nessuno | Riporta il flag di opt-in del costruttore | bool | Nessuno | — |
Pkcs11Signer::getCertificateDer() | Nessuno | Restituisce il certificato del firmatario letto dal token | string (DER) | Nessuno | Caricato una sola volta alla costruzione |
Pkcs11Signer::getCertificateChainDer() | Nessuno | Restituisce gli intermedi forniti dal costruttore | array<string> (DER) | Nessuno | Esclude 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 = null | Verifica proc_open, sonda il binario e la versione, risolve il backend e carica i certificati | — | HsmOperationException (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 0600 | string byte grezzi della firma | HsmOperationException (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 firma | Il sottoprocesso viene terminato dopo $timeoutSeconds; lo stderr viene redatto prima di raggiungere i messaggi |
Superficie di accesso OpenSslCliSigner | Nessuno | Risultati di costruzione in sola lettura | string / array<string> / OpenSslCliBackend | Nessuno | getCertificateDer, getCertificateChainDer, getPublicKeyAlgorithm, getCertificatePem, getResolvedBackend, getOpensslVersion |
HsmSignerProviderAdapter::__construct() | HsmSignerInterface $hsm, string $providerId, SignatureAlgorithm $algorithm = SignatureAlgorithm::Pkcs1v15 | Incapsula una concretizzazione HSM come SignerProviderInterface | — | Nessuno | Convenzioni per l’id del provider: pkcs11-{module-id}, openssl-cli |
HsmSignerProviderAdapter::providerId() | Nessuno | Restituisce l’id fornito dal costruttore | non-empty-string | Nessuno | — |
HsmSignerProviderAdapter::supportsAlgorithm() | SignatureAlgorithm $algo | Mappa l’enum su un nome in stile OpenSSL, poi interseca con l’insieme consentito del backend | bool | Nessuno | Rifiuta gli algoritmi solo-digest; gli id openssl-engine non annunciano nulla |
HsmSignerProviderAdapter::sign() | string $data, ?string $keyVersion = null | Invoca il signer incapsulato con l’algoritmo configurato | non-empty-string | KeyManagementException ($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'): 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): stringContratto di comportamento
Sezione intitolata “Contratto di comportamento”- Custodia delle chiavi. La chiave privata non lascia mai il confine del token.
Pkcs11Signerdelega l’operazione al token;OpenSslCliSignerpassa un riferimento alla chiave — un URI PKCS#11 — al sottoprocessoopenssl. Nessuno dei due signer può esportare la chiave. - Sessione e login.
Pkcs11Signermette 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.Pkcs11Signeraccetta inoltreecdsa-raw. Qualsiasi altro identificatore sollevaInvalidArgumentException— 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-encodedECDSA-Sig-Valueche 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-sourcedell’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 comepin-valuenell’URI, il che è osservabile nella riga di comando del processo; questa modalità è solo su opt-in. - Disciplina del sottoprocesso.
OpenSslCliSigneravvia 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$keyVersionnon nullo conKeyManagementExceptioninvece 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 sollevaSignatureFailedException. - Anteprima post-quantum.
signPqs()è protetta dal flag del costruttore$enablePostQuantume 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 parametriPkcs11PqsAlgorithmselezionato, 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à.
Casi limite e modalità di errore
Sezione intitolata “Casi limite e modalità di errore”- Costruire
Pkcs11Signersenzaext-pkcs11solleva immediatamenteHsmOperationException; 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
HsmOperationExceptionindicando 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).
OpenSslCliSignerrifiuta alla costruzione un$keyUriche 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
HsmOperationExceptioninvece di rinviare l’errore al momento della firma. - Un sottoprocesso che supera
$timeoutSecondsviene 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.
HsmSignerProviderAdaptercon l’id del provider ritiratoopenssl-enginenon annuncia alcun algoritmo, quindi una configurazione obsoleta fallisce alla selezione del provider invece che al momento della firma.
Comportamento in modalità FIPS
Sezione intitolata “Comportamento in modalità FIPS”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.
Conformità
Sezione intitolata “Conformità”| Dichiarazione | Standard | Clausola |
|---|---|---|
| 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.1 | CKA_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 204 | HashML-DSA context handling |
| La validazione FIPS 140-3 si attribuisce ai moduli crittografici tramite il CMVP. | FIPS 140-3 | CMVP 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.
Note di sviluppo
Sezione intitolata “Note di sviluppo”-
Il meccanismo di consegna del PIN segue la convenzione
pin-sourcedell’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-pkcs11prima di costruirePkcs11Signer; la costruzione fallisce rapidamente quando l’estensione è assente. Il signer CLI necessita diproc_openabilitato e di un binarioopensslcon 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
HsmSignerProviderAdapterquando il chiamante lavora tramiteSignerProviderInterface. Passa l’id canonico del provider per la classe incapsulata —pkcs11-{module-id}oopenssl-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()egetOpensslVersion()esistono per la registrazione delle prove; conservali con le prove di firma quando il tuo programma di conformità richiede la riproducibilità.
Vedi anche
Sezione intitolata “Vedi anche”- Firma con modulo di sicurezza hardware (PKCS#11) — la pagina della capacità con i passaggi di setup, configurazione e verifica.
- Sicurezza — Riferimento approfondito — la superficie di sicurezza Enterprise combinata.
- Firma — Riferimento approfondito — il produttore a lungo termine PAdES B-LT / B-LTA.
- FIPS 140 — Riferimento approfondito — la policy crittografica, la batteria di self-test e il gate
FipsSignatureEnforcer. - Anteprima PQC — Riferimento approfondito — la superficie dell’anteprima post-quantum e i suoi confini.
- Sicurezza / Firma (Core) — il signer CMS Core e i contratti di firma.
Confine di pubblicazione
Sezione intitolata “Confine di pubblicazione”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.