Aller au contenu

Contrat de fournisseur KMS

HsmSignerInterface est le contrat public qu’un tiers implémente pour fournir la garde des clés à NextPDF. Ton code détient la clé privée. Le moteur, lui, construit la structure CMS.

Fenêtre de terminal
composer require nextpdf/core:^3

NextPDF sépare l’assemblage de la signature de la garde des clés. Le moteur prépare la plage d’octets et assemble la structure CMS SignedData. Il ne détient pas la clé privée. La garde des clés est déléguée à un back end de signature via un contrat public.

Tu implémentes l’un des trois contrats publics :

  • SignerInterface. Contrat de base. Il renvoie un SignatureResult pour les données fournies. Il applique un horodatage. Il indique si la validation à long terme est prise en charge. Utilise ce contrat lorsque la logique de signature s’exécute dans le processus.
  • HsmSignerInterface. Contrat de garde des clés. L’implémentation doit effectuer l’opération de signature à l’intérieur de la frontière matérielle. La clé privée ne doit pas quitter cette frontière. Un fournisseur de système de gestion de clés implémente ce contrat.
  • DeferredSignerInterface. Extension de SignerInterface pour les back ends asynchrones. L’appelant soumet les données, reçoit un identifiant de tâche, puis récupère le résultat plus tard.

Cette page spécifie le contrat public. Elle ne décrit aucune implémentation interne de NextPDF Pro ni de NextPDF Enterprise. Une édition payante peut fournir une implémentation prise en charge de ce contrat. Tu dépends du contrat, pas de l’implémentation.

Le contrat exige que la clé privée ne quitte jamais la frontière sécurisée. Les pratiques établies vont dans le même sens. NIST SP 800-57 Part 1 Revision 5 définit la gestion des clés comme la prise en charge d’une clé pendant tout son cycle de vie. Ce cycle couvre, de manière sécurisée, la génération, le stockage, la distribution, l’utilisation et la destruction. PKCS#11 v3.1 rend cette frontière effective. Lorsqu’un objet de clé privée définit CKA_SENSITIVE à true ou CKA_EXTRACTABLE à false, le jeton ne doit pas révéler la valeur de la clé en clair en dehors du jeton.

Ton implémentation doit respecter cette exigence. Le moteur ne peut pas l’imposer à ta place. Si ta méthode sign() peut lire les octets bruts de la clé dans la mémoire du processus, la propriété de sécurité du contrat est perdue.

NextPDF\Contracts\HsmSignerInterface (stable, depuis 1.0.0) :

MéthodeRenvoieObjectif
sign(string $data, string $algorithm)stringSigne les données à l’intérieur de la frontière matérielle. Renvoie les octets bruts de la signature. Lève RuntimeException en cas d’échec.
getCertificateDer()stringRenvoie le certificat X.509 du signataire au format DER.
getCertificateChainDer()array<string>Renvoie les certificats intermédiaires, de l’émetteur jusqu’à la racine, en excluant le certificat du signataire.
getPublicKeyAlgorithm()stringRenvoie l’identifiant de l’algorithme de clé publique.

NextPDF\Contracts\SignerInterface (stable, depuis 1.0.0) :

MéthodeRenvoieObjectif
sign(string $data)SignatureResultRenvoie la structure CMS SignedData encodée en DER.
timestamp(string $signatureValue)stringRenvoie un jeton d’horodatage RFC 3161 encodé en DER.
supportsLtv()boolIndique si les données de validation à long terme peuvent être intégrées.

NextPDF\Contracts\DeferredSignerInterface (expérimental, depuis 3.0.0) étend SignerInterface en ajoutant submitForSigning(), retrieveSignature() et isComplete() pour les back ends asynchrones.

Les niveaux de signature produits par le moteur suivent les profils PAdES. ETSI EN 319 142-2 définit des profils PAdES étendus qui s’appuient sur les blocs de construction de base de EN 319 142-1. Le moteur associe les niveaux B-B, B-T, B-LT et B-LTA à ces blocs de construction. Ton signataire fournit l’opération cryptographique et le matériel de certificat nécessaires au moteur.

Voici un fournisseur minimal de type PKCS#11. L’appel de signature est délégué au jeton. La valeur de la clé n’est jamais lue dans 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 fournisseur de production valide les entrées, échoue en mode fermé en cas d’erreur du jeton et ne journalise jamais le matériel de clé ni de signature.

<?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);
}
}
  • Format des octets de signature. Renvoie les octets bruts de la signature. Pour RSA, les octets sont au format DER. Pour ECDSA, les octets sont la valeur brute r, puis la valeur s.
  • Ordre de la chaîne. getCertificateChainDer() exclut le certificat du signataire. Ordonne les intermédiaires depuis l’émetteur jusqu’à la racine.
  • Identifiants d’algorithme. sign() utilise des identifiants de style OpenSSL. getPublicKeyAlgorithm() renvoie le nom de l’algorithme X.509.
  • L’échec est en mode fermé. Lève RuntimeException pour toute erreur du jeton ou du KMS. Ne renvoie ni signature partielle ni signature vide.
  • Destruction des clés. Lorsqu’une clé atteint la fin de sa cryptopériode, détruis-la conformément à ta procédure de gestion des clés. NIST SP 800-57 Part 1 Revision 5 §8.2.1.2 indique qu’une clé doit être détruite dès qu’elle n’est plus nécessaire. La destruction elle-même suit le §8.3.4.

Résidence des données et mesures d’atténuation des données personnelles

Section intitulée « Résidence des données et mesures d’atténuation des données personnelles »

Le contrat ne transfère que les données à signer et le matériel de certificat. Il ne transfère ni le contenu du document ni les données personnelles au back end de signature. Garde la plage d’octets au minimum. Ne place aucune donnée personnelle dans les champs de motif ou d’emplacement de signature. Ces champs sont observables dans le fichier signé.

Ne journalise jamais les données transmises à sign(), les octets de signature renvoyés, l’identifiant de clé sous une forme récupérable, ni aucun composant privé de certificat. Journalise uniquement le résultat de l’opération et une référence non réversible. Le hook SignatureAppliedEvent constitue l’ancre d’audit prise en charge. Consulte Déclencheurs d’action.

ActifMenaceAtténuation
Clé privéeFuite dans la mémoire du processusLe contrat exige que la signature ait lieu dans la frontière ; PKCS#11 CKA_SENSITIVE / CKA_EXTRACTABLE imposent la non-extractabilité
Oracle de signatureRequêtes de signature non bornéesL’implémentation limite le débit et authentifie les appelants
Chaîne de certificatsSubstitutionL’implémentation renvoie une chaîne qui remonte jusqu’à une racine de confiance
Octets de signatureDivulgation par les journauxLe chemin d’erreur échoue en mode fermé ; aucun matériel de signature n’est présent dans la télémétrie
Clé au-delà de la cryptopériodeUtilisation continueDestruction des clés conformément à NIST SP 800-57 Part 1 Revision 5 §8.2.1.2

Les niveaux de signature sont conformes aux profils PAdES. ETSI EN 319 142-2 §5.1 définit des profils PAdES étendus à partir des blocs de construction de base de EN 319 142-1. Le moteur assemble ces blocs de construction à partir du matériel fourni par ton signataire. La gestion des clés s’aligne sur le cycle de vie de NIST SP 800-57 Part 1 Revision 5, y compris l’exigence de destruction du §8.2.1.2. La garde matérielle des clés s’aligne sur les attributs de clé non extractible de PKCS#11 v3.1. Les citations sont consignées dans l’en-tête de la page.

Contrôle des exportations et gouvernance de la revue

Section intitulée « Contrôle des exportations et gouvernance de la revue »

Cette page couvre la garde des clés via PKCS#11 et par module de sécurité matériel, donc son en-tête définit export_control_class: legal-review-required. Selon la politique de revue de la documentation (plan §17, porte 6), toute page comportant un mode de sécurité, un chemin ou un contenu correspondant à PAdES, FIPS, HSM ou PKCS#11 exige la validation de l’équipe GitHub @nextpdf-labs/crypto-reviewers avant de pouvoir être publiée. Cette approbation CODEOWNERS constitue une porte de fusion stricte : la page reste publish: false jusqu’à ce que la revue légale de contrôle des exportations et la revue @nextpdf-labs/crypto-reviewers soient toutes deux terminées.

NextPDF Enterprise fournit une implémentation prise en charge de ce contrat, avec garde des clés par système de gestion de clés, assemblage de chaîne de certificats et intégration d’audit. Soit tu implémentes HsmSignerInterface toi-même dans le cœur, soit tu consommes l’implémentation Enterprise via le même contrat public sans changement de code.

Le glossaire définit key management system, cryptoperiod et HSM ; consulte le glossaire publié pour leurs définitions canoniques.