Salta ai contenuti

Contratto del provider KMS

HsmSignerInterface è il contratto pubblico che una terza parte implementa per fornire a NextPDF la custodia delle chiavi. Il codice del chiamante conserva la chiave privata. Il motore costruisce la struttura CMS.

Terminal window
composer require nextpdf/core:^3

NextPDF separa l’assemblaggio della firma dalla custodia delle chiavi: il motore prepara l’intervallo di byte e assembla la struttura CMS SignedData, senza conservare la chiave privata. La custodia delle chiavi viene delegata a un back-end di firma tramite un contratto pubblico.

È possibile implementare uno dei tre contratti pubblici:

  • SignerInterface. Il contratto di base. Restituisce un SignatureResult per i dati specificati, applica una marca temporale e segnala il supporto per la convalida a lungo termine. Usare questo contratto quando la logica di firma viene eseguita all’interno del processo.
  • HsmSignerInterface. Il contratto per la custodia delle chiavi. L’implementazione deve eseguire l’operazione di firma all’interno del confine hardware. La chiave privata non deve uscire da tale confine. Un provider basato su un sistema di gestione delle chiavi implementa questo contratto.
  • DeferredSignerInterface. Un’estensione di SignerInterface per i back-end asincroni. Il chiamante invia i dati, riceve un identificatore del processo e recupera il risultato in un secondo momento.

Questa pagina definisce il contratto pubblico. Non descrive alcuna implementazione interna di NextPDF Pro o NextPDF Enterprise. Un’edizione a pagamento può fornire un’implementazione supportata di questo contratto. La dipendenza riguarda il contratto, non l’implementazione.

Il contratto richiede che la chiave privata non lasci mai il confine sicuro. La prassi standard sostiene questo requisito. NIST SP 800-57 Part 1 Revision 5 definisce la gestione delle chiavi come la gestione di una chiave lungo l’intero ciclo di vita. Tale ciclo di vita comprende generazione, archiviazione, distribuzione, uso e distruzione sicuri. PKCS#11 v3.1 rende applicabile il confine. Quando un oggetto chiave privata imposta CKA_SENSITIVE su true o CKA_EXTRACTABLE su false, il token non deve rivelare il valore della chiave in chiaro all’esterno del token.

L’implementazione è responsabile del rispetto di questo requisito. Il motore non può applicarlo automaticamente. Se il metodo sign() può leggere i byte grezzi della chiave nella memoria del processo, la proprietà di sicurezza del contratto viene meno.

NextPDF\Contracts\HsmSignerInterface (stabile, dalla versione 1.0.0):

MetodoRestituisceScopo
sign(string $data, string $algorithm)stringFirma i dati all’interno del confine hardware. Restituisce i byte grezzi della firma. Genera RuntimeException in caso di errore.
getCertificateDer()stringRestituisce il certificato X.509 del firmatario in formato DER.
getCertificateChainDer()array<string>Restituisce i certificati intermedi, dall’emittente alla radice, escludendo il certificato del firmatario.
getPublicKeyAlgorithm()stringRestituisce l’identificatore dell’algoritmo della chiave pubblica.

NextPDF\Contracts\SignerInterface (stabile, dalla versione 1.0.0):

MetodoRestituisceScopo
sign(string $data)SignatureResultRestituisce il CMS SignedData con codifica DER.
timestamp(string $signatureValue)stringRestituisce un token di marca temporale RFC 3161 con codifica DER.
supportsLtv()boolIndica se i dati di convalida a lungo termine possono essere incorporati.

NextPDF\Contracts\DeferredSignerInterface (sperimentale, dalla versione 3.0.0) estende SignerInterface con submitForSigning(), retrieveSignature() e isComplete() per i back-end asincroni.

I livelli di firma prodotti dal motore seguono i profili PAdES. ETSI EN 319 142-2 definisce profili PAdES estesi basati sui blocchi costitutivi di base della EN 319 142-1. Il motore associa i livelli B-B, B-T, B-LT e B-LTA a tali blocchi costitutivi. Il firmatario fornisce al motore l’operazione crittografica e il materiale del certificato necessari.

Questo esempio mostra un provider minimale in stile PKCS#11. La chiamata di firma viene delegata al token. Il valore della chiave non viene mai letto in PHP.

<?php
declare(strict_types=1);
use NextPDF\Contracts\HsmSignerInterface;
final class TokenSigner implements HsmSignerInterface
{
public function __construct(private readonly TokenSession $session) {}
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
{
// The token computes the signature. The key stays inside the token.
return $this->session->c_sign($data, $algorithm);
}
public function getCertificateDer(): string
{
return $this->session->readCertificate();
}
/** @return array<string> */
public function getCertificateChainDer(): array
{
return $this->session->readChain();
}
public function getPublicKeyAlgorithm(): string
{
return 'rsaEncryption';
}
}

Un provider di produzione convalida gli input, fallisce in modo fail-closed in caso di errore del token e non registra mai materiale relativo a chiavi o firme.

<?php
declare(strict_types=1);
use NextPDF\Contracts\HsmSignerInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
final class KmsSigner implements HsmSignerInterface
{
public function __construct(
private readonly RemoteKmsClient $kms,
private readonly string $keyId,
private readonly LoggerInterface $logger,
) {}
public function sign(string $data, string $algorithm = 'sha256WithRSAEncryption'): string
{
if ($data === '') {
throw new RuntimeException('Refusing to sign empty data');
}
try {
// The KMS performs the operation. The key never reaches this process.
return $this->kms->sign($this->keyId, $data, $algorithm);
} catch (\Throwable $error) {
// Fail closed. Do not log key material or signature bytes.
$this->logger->error('kms.sign.failed', ['key' => $this->keyId]);
throw new RuntimeException('KMS signing failed', previous: $error);
}
}
public function getCertificateDer(): string
{
return $this->kms->certificate($this->keyId);
}
/** @return array<string> */
public function getCertificateChainDer(): array
{
return $this->kms->chain($this->keyId);
}
public function getPublicKeyAlgorithm(): string
{
return $this->kms->algorithm($this->keyId);
}
}
  • Formato dei byte della firma. Restituire i byte grezzi della firma. Per RSA, i byte sono in formato DER. Per ECDSA, i byte sono il valore r grezzo seguito dal valore s.
  • Ordine della catena. getCertificateChainDer() esclude il certificato del firmatario. Ordinare i certificati intermedi dall’emittente alla radice.
  • Identificatori dell’algoritmo. sign() usa identificatori in stile OpenSSL. getPublicKeyAlgorithm() restituisce il nome dell’algoritmo X.509.
  • Il fallimento è fail-closed. Generare RuntimeException in caso di qualsiasi errore del token o del KMS. Non restituire una firma parziale o vuota.
  • Distruzione della chiave. Quando una chiave raggiunge la fine del proprio crittoperiodo, distruggerla secondo la procedura di gestione delle chiavi. NIST SP 800-57 Part 1 Revision 5 §8.2.1.2 afferma che una chiave dovrebbe essere distrutta non appena non è più necessaria. La distruzione stessa segue il §8.3.4.

Residenza dei dati e mitigazioni dei dati personali

Sezione intitolata “Residenza dei dati e mitigazioni dei dati personali”

Il contratto trasferisce solo i dati da firmare e il materiale del certificato. Non trasferisce al back-end di firma né il contenuto del documento né dati personali. Mantenere l’intervallo di byte al minimo. Non inserire dati personali nei campi del motivo o della località di firma. Tali campi sono osservabili nel file firmato.

Non registrare mai i dati passati a sign(), i byte di firma restituiti, l’identificatore della chiave in forma recuperabile o qualsiasi componente privato del certificato. Registrare solo l’esito dell’operazione e un riferimento non reversibile. L’hook SignatureAppliedEvent è l’ancora di audit supportata. Vedere Trigger di azione.

AssetMinacciaMitigazione
Chiave privataEsposizione nella memoria del processoIl contratto richiede la firma all’interno del confine; PKCS#11 CKA_SENSITIVE / CKA_EXTRACTABLE impongono la non estraibilità
Oracolo di firmaRichieste di firma illimitateL’implementazione limita la frequenza e autentica i chiamanti
Catena di certificatiSostituzioneL’implementazione restituisce una catena che risale a una radice attendibile
Byte della firmaDivulgazione tramite logPercorso di errore fail-closed; nessun materiale di firma nella telemetria
Chiave oltre il crittoperiodoUso continuativoDistruzione della chiave secondo NIST SP 800-57 Part 1 Revision 5 §8.2.1.2

I livelli di firma sono conformi ai profili PAdES. ETSI EN 319 142-2 §5.1 definisce profili PAdES estesi sui blocchi costitutivi di base della EN 319 142-1. Il motore assembla tali blocchi costitutivi a partire dal materiale fornito dal firmatario. La gestione delle chiavi è allineata al ciclo di vita di NIST SP 800-57 Part 1 Revision 5, incluso il requisito di distruzione del §8.2.1.2. La custodia delle chiavi tramite hardware è allineata agli attributi di chiave non estraibile di PKCS#11 v3.1. Le citazioni sono registrate nel front matter della pagina.

Controllo delle esportazioni e governance delle revisioni

Sezione intitolata “Controllo delle esportazioni e governance delle revisioni”

Questa pagina riguarda la custodia delle chiavi tramite PKCS#11 e modulo di sicurezza hardware; per questo il suo front matter imposta export_control_class: legal-review-required. In base ai criteri di revisione della documentazione (piano §17 gate 6), qualsiasi pagina con una modalità di sicurezza oppure con un percorso o contenuto corrispondente a PAdES, FIPS, HSM o PKCS#11 richiede l’approvazione del team GitHub @nextpdf-labs/crypto-reviewers prima di poter essere pubblicata. Tale approvazione CODEOWNERS è un gate di merge vincolante: la pagina resta publish: false finché non vengono completate sia la revisione legale per il controllo delle esportazioni sia la revisione @nextpdf-labs/crypto-reviewers.

NextPDF Enterprise fornisce un’implementazione supportata di questo contratto con custodia tramite sistema di gestione delle chiavi, assemblaggio della catena di certificati e integrazione dell’audit. È possibile implementare HsmSignerInterface in autonomia in Core oppure utilizzare l’implementazione Enterprise tramite lo stesso contratto pubblico, senza modifiche al codice.

Il glossario definisce sistema di gestione delle chiavi, crittoperiodo e HSM; per ciascuna definizione canonica consultare il glossario pubblicato.